├── .github └── workflows │ └── ci.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── README.md ├── buildspec.yml ├── dotbare ├── dotbare.plugin.bash ├── dotbare.plugin.zsh ├── helper ├── get_confirmation.sh ├── git_query.sh ├── preview.sh ├── search_file.sh └── set_variable.sh ├── pkg ├── completion │ ├── bash │ │ └── dotbare │ └── zsh │ │ └── _dotbare ├── dotbare.aur └── dotbare.brew ├── scripts ├── fadd ├── fbackup ├── fcheckout ├── fedit ├── fgrep ├── finit ├── flog ├── freset ├── fstash ├── fstat ├── funtrack └── fupgrade └── tests ├── Dockerfile ├── README.md ├── dotbare.bats ├── fadd.bats ├── fbackup.bats ├── fcheckout.bats ├── fedit.bats ├── fgrep.bats ├── finit.bats ├── flog.bats ├── freset.bats ├── fstash.bats ├── fstat.bats ├── funtrack.bats ├── fupgrade.bats ├── fzf ├── git ├── set_variable.bats ├── shellcheck.sh └── tree /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | COLUMNS: 80 7 | 8 | defaults: 9 | run: 10 | shell: bash 11 | working-directory: . 12 | 13 | jobs: 14 | ubuntu: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | - run: sudo apt-get install shellcheck -y 19 | - run: ./tests/shellcheck.sh 20 | - uses: actions/setup-node@v2 21 | with: 22 | node-version: "13" 23 | - run: npm install -g bats 24 | - run: ./dotbare finit -u https://github.com/kazhala/dotfiles.git 25 | - run: bats tests 26 | - run: rm -rf "$HOME"/.cfg 27 | - run: ./dotbare finit -y 28 | - run: bats tests 29 | macos: 30 | runs-on: macos-latest 31 | steps: 32 | - uses: actions/checkout@v2 33 | - run: brew install shellcheck 34 | - run: ./tests/shellcheck.sh 35 | - run: brew install bats 36 | - run: ./dotbare finit -u https://github.com/kazhala/dotfiles.git 37 | - run: bats tests 38 | - run: rm -rf "$HOME"/.cfg 39 | - run: ./dotbare finit -y 40 | - run: bats tests 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | scripts/* 2 | !scripts/fadd 3 | !scripts/fbackup 4 | !scripts/fcheckout 5 | !scripts/fedit 6 | !scripts/finit 7 | !scripts/flog 8 | !scripts/freset 9 | !scripts/fstash 10 | !scripts/fstat 11 | !scripts/funtrack 12 | !scripts/fupgrade 13 | !scripts/fgrep 14 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | Noteble changes are documentated in this file. 4 | 5 | ## dev 6 | 7 | ### Fixed 8 | 9 | - unnecessary argument for zsh completion [#26](https://github.com/kazhala/dotbare/issues/26) 10 | 11 | ### Added 12 | 13 | - common basic zsh widgets such as `dotbare fedit` [#24](https://github.com/kazhala/dotbare/issues/24) 14 | - new zsh widget `dotbare-transform` (Not documented yet, will add to documendation in next release) 15 | - transform a generic `git` command to a `dotbare` command; e.g. `git log` -> `dotbare -g flog` 16 | - Bind this widget to keys of your choice (e.g. `ctrl-u`): `bindkey "^u" dotbare-transform` 17 | 18 | ## 1.3.1 (25/08/2020) 19 | 20 | ### Fixed 21 | 22 | - dotbare with no args fails [#23](https://github.com/kazhala/dotbare/issues/23) 23 | - some typos in help manual 24 | 25 | ## 1.3.0 (04/08/2020) 26 | 27 | ### Added 28 | 29 | - hide preview window on small window (when \$COLUMNS less than 80) 30 | - If using default keybinds, use `alt-t` to re-open the preview 31 | - verbose flag completion for bash 32 | - `dotbare` can now be used as a generic fuzzy git tool, using `-g` or `--git flag` 33 | - Sort of like a replacement for `forgit`, bascially just dynamiclly switching 34 | `DOTBARE_DIR` and `DOTBARE_TREE` to the current git directory. 35 | - Seems kind of wierd to make `dotbare` also a fuzzy git client, but since it's literally 36 | like a few lines of changes, I figured why not .. 37 | - options for `fgrep` to configure search behavior in fzf 38 | - `-c, --col`: pass in argument to specify which column to start searching in fzf (`dotbare fgrep --col 2`), by default `fgrep` starts the search from column 3, column 1 is the file name, column2 is the line number and starting from column 3 is the actual content. 39 | - `-f, --full`: configure the fzf search to include all columns, same as using `dotbare fgrep --col 1` which includes the file name, line number and the actual content. 40 | - dedicated completion file to use for package installation 41 | 42 | ### CHANGED 43 | 44 | - update the fzf header to make more sense, some wording issues 45 | 46 | ### Fixed 47 | 48 | - bash completion raising unexpected git error 49 | 50 | ## 1.2.3 (17/07/2020) 51 | 52 | ### Added 53 | 54 | - zsh completion for dotbare commands 55 | - zsh completion for git commands 56 | - bash completion for git commands 57 | - fgrep: grep words within tracked dotfiles and edit them through EDITOR 58 | - More info is documented in wiki 59 | 60 | ### Changed 61 | 62 | - adjusted how help messages are printed to reduce some calls 63 | 64 | ### Fixed 65 | 66 | - bash completion awk panic on version 4.0+ bash on MacOS 67 | 68 | ## 1.2.2 (11/07/2020) 69 | 70 | ### Fixed 71 | 72 | - dotbare crash when migrating a dotfile repo with over 100 files [#12](https://github.com/kazhala/dotbare/issues/12) 73 | - dotbare fbackup crash when using cp command on symlink 74 | 75 | ## 1.2.1 (09/07/2020) 76 | 77 | ### Added 78 | 79 | - dynamic preview function, detect bats, hightlight etc to provide syntax hightlighting when previewing files. 80 | - custom preview ENV variable (DOTBARE_PREVIEW) 81 | - Note: has to be this format `export DOTBARE_PREVIEW='cat -n {}'`, the `{}` is 82 | used in preview functions to subsitute for the filepath. 83 | - support for fancy diff tools like "diff-so-fancy" or "delta" 84 | - This is optional, only takes effect if installed and set as `git config core.pager` 85 | - Also configurable through DOTBARE_DIFF_PAGER, these are documentated in the README. 86 | 87 | ## 1.2.0 (01/07/2020) 88 | 89 | ### Added 90 | 91 | - `dotbare` now accept verbose type of argument e.g. `dotbare fadd --file` `dotbare fcheckout --branch`. 92 | More information please refer to each commands help manual 93 | - support for handling files with spaces 94 | - improved unittest with mocking 95 | - more reliable `dotbare fupgrade` behavior 96 | - version flag for `dotbare`, `dotbare --version` or `dotbare -v` 97 | 98 | ### Changed 99 | 100 | - `dotbare fcheckout -a` has now been renamed to `dotbare fcheckout -s` or `dotbare fcheckout --select` 101 | - `dotbare fstash -f` has now been renamed to `dotbare fstash -s` or `dotbare fstash --select` 102 | - `dotbare funtrack -s` has now been renamed to `dotbare funtrack -t` or `dotbare funtrack --temp` 103 | - `dotbare funtrack -S` has now been renamed to `dotbare funtrack -r` or `dotbare funtrack --resume` 104 | - dryrun information no longer will display if `-y` or `--yes` flag has been passed 105 | 106 | ### Removed 107 | 108 | - removed `-a` flag of `dotbare freset`. It's not working as intended because I misunderstand it, the intended 109 | behavior is actually achieved by `dotbare fcheckout -a`, use `dotbare fcheckout -a` instead. 110 | (Edit: `dotbare fcheckout -a` is now `dotbare fcheckout -s` or `dotbare fcheckout --select`) 111 | 112 | ## 1.1.0 (28/06/2020) 113 | 114 | ### Added 115 | 116 | - zsh plugin [#4](https://github.com/kazhala/dotbare/pull/4) 117 | - bash plugin 118 | - drop-in functionality [#6](https://github.com/kazhala/dotbare/pull/6) 119 | - User can now place custom fzf scripts into scripts folder 120 | - bash completion capabilities [#7](https://github.com/kazhala/dotbare/pull/7) 121 | - option to clone submodule [#8](https://github.com/kazhala/dotbare/issues/8) 122 | 123 | ### Fixed 124 | 125 | - ambiguous argument error [#3](https://github.com/kazhala/dotbare/pull/3) 126 | 127 | ### Removed 128 | 129 | - removed global .gitignore manipulation during migration, not needed. Added .gitignore tips to README and 130 | let user handle it 131 | 132 | ## 1.0.0 (20/05/2020) 133 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to dotbare 2 | 3 | Thanks for stopping by! Happy to see you willing to improve `dotbare`. 4 | 5 | `dotbare` has lots of improvement that could be made ranging from code efficiency, 6 | functionality and possibility some best practice for safer code or portability. 7 | 8 | ## Efficiency 9 | 10 | If you find some weird implementations that could be shorten or done better, feel free 11 | to make a PR for it, I'm willing to learn how to improve and done better. For example, 12 | before v1.2.3, the help message from `dotbare` were actually printed through multiple 13 | invocations of `echo -e` which were very very unnecessary. 14 | 15 | ```sh 16 | # Before 17 | echo -e "usage: ...\n" 18 | echo -e "foo boo\n" 19 | echo -e "Optional arguments: ...\n" 20 | 21 | # After 22 | echo -e "usage: ... 23 | 24 | foo boo 25 | 26 | Optional arguments: ..." 27 | ``` 28 | 29 | ## Functionality 30 | 31 | `dotbare` was originally implemented to fill my own need with some extra that I think 32 | others may use. There are two ways to improve functionality, adding new "f" scripts 33 | or maybe adding extra flags for existing scripts. 34 | 35 | ### New scripts 36 | 37 | Checkout [wiki](https://github.com/kazhala/dotbare/wiki/Custom-Scripts) about how 38 | to create custom scripts as well as how to use the API from `dotbare` helper methods. 39 | 40 | Feel free to open pull request for your script, I'm happy to review and discuss for merging. 41 | 42 | Just make sure that they are indeed a separate category than all of the existing "f" scripts, 43 | otherwise you may want to add extra flags to existing "f" scripts. 44 | 45 | Before you could commit your custom scripts to the fork of `dotbare`, you need to add an 46 | entry to `.gitignore` because it's written to ignore everything in the scripts folder. 47 | 48 | ```sh 49 | # ignore everything in scripts folder except the !scripts/fadd etc 50 | scripts/* 51 | !scripts/fadd 52 | !scripts/fbackup 53 | .... 54 | !scripts/your new script 55 | ``` 56 | 57 | ### Adding arguments 58 | 59 | Existing "f" scripts could be extended through adding flags. For example maybe `dotbare fgrep` 60 | could take a `--dryrun` option, instead of populating result in fzf, just print the result 61 | to terminal. 62 | 63 | After adding the new flag, don't forget to add the flag to `usage` function as well as `dotbare.plugin.zsh` 64 | completion definitions. 65 | 66 | ## Helper functions 67 | 68 | When making changes or extending helper functions like `git_query.sh`, make sure the changes are 69 | backward compatible. 70 | 71 | ## Testing 72 | 73 | There is no requirements for the changes to be unit tested, bash unit test is nasty. 74 | 75 | Just make sure you have thoroughly tested manually and pass shellcheck. 76 | 77 | If you are interested, checkout [here](https://github.com/kazhala/dotbare/blob/master/tests/README.md) to see how the unit test are implemented and 78 | use current unit tests as reference. 79 | 80 | ## Finally 81 | 82 | Thanks for your interest in improving `dotbare`! 83 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM bash:latest 2 | RUN apk add --no-cache git 3 | RUN apk add --no-cache vim 4 | RUN apk add --no-cache fzf 5 | ADD ./ /root/dotbare 6 | RUN echo "source /root/dotbare/dotbare.plugin.bash" >> "$HOME"/.bashrc 7 | WORKDIR /root 8 | ENTRYPOINT ["bash"] 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Kevin Zhuang 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dotbare 2 | 3 | ![CI Status](https://github.com/kazhala/dotbare/workflows/CI/badge.svg) 4 | ![AWSCodeBuild](https://codebuild.ap-southeast-2.amazonaws.com/badges?uuid=eyJlbmNyeXB0ZWREYXRhIjoiVVo4eUt6T0JGSFU1M1plVml0Y1dOWkJnaTV0eWZNNm5uY043Z3MwaUY2aUhaTHllQklhaVFiWmxIcTNVc0ZFRFhwbFdpZ3dsb3RMZFU0aDk3S1FUQUpRPSIsIml2UGFyYW1ldGVyU3BlYyI6ImVUdjloSlNTa3NyTUJVemIiLCJtYXRlcmlhbFNldFNlcmlhbCI6MX0%3D&branch=master) 5 | ![Platform](https://img.shields.io/badge/platform-macos%20%7C%20linux-blue) 6 | ![License](https://img.shields.io/badge/license-MIT-green) 7 | 8 | ## Introduction 9 | 10 | `dotbare` is a command line utility to help manage dotfiles and or as a generic fuzzy git client. As a dotfile management tool, 11 | it wraps around git bare repository, query git information from it and display them through [fzf](https://github.com/junegunn/fzf) for an 12 | interactive experience. It is originally inspired by [forgit](https://github.com/wfxr/forgit), a git wrapper using fzf. 13 | `dotbare` uses a different implementation approach and focuses on managing and interacting with system dotfiles. Because 14 | of the flexible implementation of `dotbare`, it can easily integrate with symlink/GNU stow setup or even as a generic 15 | fuzzy git client to use in any git repository. 16 | 17 | As a generic fuzzy git client (using `--git` flag), `dotbare` dynamically determine the top level `.git` folder and process git information 18 | and perform git operation in the current working tree. 19 | 20 | You could find out how git bare repository could be used for managing dotfiles [here](https://www.atlassian.com/git/tutorials/dotfiles). 21 | Or a [video](https://www.youtube.com/watch?v=tBoLDpTWVOM&t=288s) explanation that helped me to get started. If you are currently 22 | using a symlink/GNU stow setup, checkout how to integrate `dotbare` with them [here](#migrating-from-a-generic-symlink-setup-or-gnu-stow). 23 | 24 | Select and edit dotfiles. 25 | ![fedit](https://user-images.githubusercontent.com/43941510/87669391-37f28180-c7b1-11ea-907d-3b26f363a279.png) 26 | Stage and unstage dotfiles. 27 | ![fstat](https://user-images.githubusercontent.com/43941510/87669408-43de4380-c7b1-11ea-8a31-fc702eb69804.png) 28 | Interactive log viewer. 29 | ![flog](https://user-images.githubusercontent.com/43941510/87669399-3e80f900-c7b1-11ea-9bfa-5db31c4307c3.png) 30 | For more capabilities and commands, checkout [wiki](https://github.com/kazhala/dotbare/wiki/Commands). 31 | 32 | ## Why 33 | 34 | It has always been a struggle for me to get started with managing dotfiles using version control, 35 | as tools like "GNU stow" really scares me off with all the symlinks, until I found 36 | out about using git bare repository for managing dotfiles, zero symlinks, minimal setup 37 | required while keeping dotfiles at the location they should be. 38 | 39 | However, it has always lack some interactive experience as it does not provide any auto 40 | completion on git commands nor file paths by default. It is also a pain when migrating the setup over 41 | to another system as you will have to manually resolve all the git checkout issues. 42 | 43 | `dotbare` solves the above problems by providing a series of scripts starts with a prefix f 44 | (e.g. `dotbare fadd`, `dotbare flog` etc) that will enable a interactive experience by processing 45 | all the git information and display it through fzf. In addition, `dotbare` also comes with command line completion 46 | that you could choose to either to complete `git` commands or `dotbare` commands. 47 | `dotbare` also comes with the ability to integrate with GNU stow or any symlink set up as long as you are using git. 48 | It is easy to migrate to any system with minimal set up required. In addition, with a simple flag `--git`, you can 49 | now also use `dotbare` as a generic fuzzy git client to manage any git repository. 50 | 51 | ## Install 52 | 53 | ### zsh 54 | 55 | `dotbare` should work with any zsh plugin manager, below is only demonstration. Checkout [wiki](https://github.com/kazhala/dotbare/wiki/Completion#zsh) 56 | about how to enable completion for zsh. 57 | 58 | #### zinit 59 | 60 | ```sh 61 | zinit light kazhala/dotbare 62 | ``` 63 | 64 | #### Fig 65 | 66 | [Fig](https://fig.io) adds apps, shortcuts, and autocomplete to your existing terminal. 67 | 68 | Install `dotbare` in just one click. 69 | 70 | 71 | 72 | 73 | #### oh-my-zsh 74 | 75 | - Clone the repository in to [oh-my-zsh](https://github.com/ohmyzsh/ohmyzsh) plugins directory. 76 | 77 | ```sh 78 | git clone https://github.com/kazhala/dotbare.git $HOME/.oh-my-zsh/custom/plugins/dotbare 79 | ``` 80 | 81 | - Activate the plugin in `~/.zshrc`. 82 | 83 | ```zsh 84 | plugins=( [plugins...] dotbare [plugins...] ) 85 | ``` 86 | 87 | #### Antigen 88 | 89 | ```sh 90 | antigen bundle kazhala/dotbare 91 | ``` 92 | 93 | #### Manual 94 | 95 | - Clone the repository (change ~/.dotbare to the location of your preference). 96 | 97 | ```sh 98 | git clone https://github.com/kazhala/dotbare.git ~/.dotbare 99 | ``` 100 | 101 | - Put below into `.zshrc`. 102 | 103 | ```sh 104 | source ~/.dotbare/dotbare.plugin.zsh 105 | ``` 106 | 107 | ### bash 108 | 109 | `dotbare` comes with a `dotbare.plugin.bash` which contains the command line completion 110 | function for both `git` and `dotbare`, checkout [wiki](https://github.com/kazhala/dotbare/wiki/Completion#bash) 111 | about how to enable it. 112 | 113 | - Clone the repository (change ~/.dotbare to the location of your preference). 114 | 115 | ```sh 116 | git clone https://github.com/kazhala/dotbare.git ~/.dotbare 117 | ``` 118 | 119 | - Put below into `.bashrc` or `.bash_profile`. 120 | 121 | ```sh 122 | source ~/.dotbare/dotbare.plugin.bash 123 | ``` 124 | 125 | ### others 126 | 127 | 1. Clone the repository (change ~/.dotbare to the location of your preference). 128 | 129 | ```sh 130 | git clone https://github.com/kazhala/dotbare.git ~/.dotbare 131 | ``` 132 | 133 | 2. Add `dotbare` to your PATH. 134 | 135 | ```sh 136 | # This is only an example command for posix shell 137 | # If you are on fish, use the fish way to add dotbare to your path 138 | export PATH=$PATH:$HOME/.dotbare 139 | ``` 140 | 141 | Or you could create a alias which point to dotbare executable. 142 | 143 | ```sh 144 | alias dotbare="$HOME/.dotbare/dotbare" 145 | ``` 146 | 147 | ## Getting started 148 | 149 | ### Dependencies 150 | 151 | You will need git on the system for obvious reasons..and because `dotbare` is written in bash, 152 | it will require you to have bash in the system (You don't need to run bash, just need to be in the system). 153 | 154 | #### Required dependency 155 | 156 | - [fzf](https://github.com/junegunn/fzf) 157 | 158 | #### Optional dependency 159 | 160 | - [tree](https://linux.die.net/man/1/tree) (Provide a directory tree view when finding directory) 161 | 162 | ```sh 163 | # if you are on macos 164 | brew install tree 165 | ``` 166 | 167 | - [bat](https://github.com/sharkdp/bat) or [highlight](http://www.andre-simon.de/doku/highlight/en/highlight.php) or [coderay](https://github.com/rubychan/coderay) 168 | or [rougify](https://github.com/rouge-ruby/rouge) (Syntax highlighting when previewing files, otherwise cat will be used) 169 | - [delta](https://github.com/dandavison/delta) or [diff-so-fancy](https://github.com/so-fancy/diff-so-fancy) 170 | or any diff tools of your choice (Fancy git diff preview like in the screen shot) 171 | 172 | ### Setup 173 | 174 | 1. init git bare repository. 175 | 176 | Note: by default, `dotbare finit` will set up a bare repository in \$HOME/.cfg, to customize 177 | location and various other settings, checkout [customization](#customization) 178 | 179 | ```sh 180 | dotbare finit 181 | ``` 182 | 183 | 2. add dotfiles you want to track. 184 | 185 | Treat `dotbare` as normal `git` commands. 186 | 187 | ```sh 188 | dotbare fadd -f 189 | # or 190 | dotbare add [FILENAME] 191 | 192 | # add entire repository like .config directory 193 | dotbare fadd -d 194 | # or 195 | dotbare add [DIRECTORY] 196 | ``` 197 | 198 | 3. commit changes and push to remote. 199 | 200 | ```sh 201 | dotbare commit -m "First commit" 202 | dotbare remote add origin [URL] 203 | dotbare push -u origin master 204 | ``` 205 | 206 | ### Migration 207 | 208 | #### Migrating from normal git bare repository 209 | 210 | 1. follow the steps in [install](#install) to install `dotbare`. 211 | 2. check your current alias of git bare reference. 212 | 213 | ```sh 214 | # Below is an example alias, check yours for reference 215 | alias config=/usr/bin/git --git-dir=$HOME/.cfg --work-tree=$HOME 216 | ``` 217 | 218 | 3. set env variable for `dotbare`. 219 | 220 | ```sh 221 | export DOTBARE_DIR="$HOME/.cfg" 222 | export DOTBARE_TREE="$HOME" 223 | ``` 224 | 225 | 4. remove the original alias and use `dotbare`. 226 | 227 | 5. optionally you could alias `config` to `dotbare` so you keep your muscle memory. 228 | 229 | ```sh 230 | alias config=dotbare 231 | ``` 232 | 233 | #### Migrating from a generic symlink setup or GNU stow 234 | 235 | ##### Keep your current setup but integrate dotbare 236 | 237 | 1. follow the steps in [install](#install) to install `dotbare`. 238 | 2. set environment variable so that `dotbare` knows where to look for git information. 239 | 240 | ```sh 241 | # e.g. I have all my dotfiles stored in folder $HOME/.myworld and symlinks all of them to appropriate location. 242 | # export DOTBARE_DIR="$HOME/.myworld/.git" 243 | # export DOTBARE_TREE="$HOME/.myworld" 244 | export DOTBARE_DIR= 245 | export DOTBARE_TREE= 246 | ``` 247 | 248 | 3. Run `dotbare` anywhere in your system. 249 | 250 | Note: with this method, you do not run `dotbare finit -u [URL]` when migrating to new system, 251 | you will do your normal migration steps and then do the above steps. 252 | 253 | ##### Complete migration 254 | 255 | While bare method is great and easy, I recommend keeping your current symlink/GNU stow setup and integrate it with `dotbare` instead of a migration. 256 | If you are really happy with `dotbare`, as long as your remote repository resembles the structure of your home holder 257 | (reference what I mean in my [repo](https://github.com/kazhala/dotfiles.git)), simply run the command below. 258 | 259 | **Disclaimer**: I have not done nearly enough test on this as I don't personally use symlink/GNU stow setup, migrate this way with caution. 260 | I recommend you test this migration in docker, see [Test-it-in-docker](#test-it-in-docker). 261 | 262 | ```sh 263 | # dotbare will replace all symlinks with the original file and a bare repository will be created at $DOTBARE_DIR 264 | dotbare finit -u [URL] 265 | ``` 266 | 267 | #### Migrating dotbare to a new system 268 | 269 | 1. follow the steps in [install](#install) to install `dotbare`. 270 | 2. Optionally set env variable to customize `dotbare` location (checkout [customization](#customization)). 271 | 272 | ```sh 273 | export DOTBARE_DIR="$HOME/.cfg" 274 | export DOTBARE_TREE="$HOME" 275 | ``` 276 | 277 | 3. give `dotbare` your remote URL and let it handle the rest. 278 | 279 | ```sh 280 | dotbare finit -u https://github.com/kazhala/dotfiles.git 281 | ``` 282 | 283 | #### Test it in docker 284 | 285 | When you are about to do migrations, I strongly suggest you give the migration a try in docker first. 286 | The `dotbare` image is based on alpine linux. 287 | 288 | ```sh 289 | docker pull kazhala/dotbare:latest 290 | docker container run -it --rm --name dotbare kazhala/dotbare:latest 291 | ``` 292 | 293 | ![migration demo](https://user-images.githubusercontent.com/43941510/82392054-3ee96600-9a86-11ea-9ea9-158452c62d06.gif) 294 | 295 | ## Customization 296 | 297 | `dotbare` could be customized through modification of env variables. 298 | 299 | Note: customization of fzf is not covered here, checkout their [wiki](https://github.com/junegunn/fzf/wiki). 300 | 301 | ### DOTBARE_DIR 302 | 303 | This is the location of the bare repository, `dotbare` will look for this directory 304 | and query git information or it will create this directory when initializing `dotbare`. 305 | Change this to location or rename the directory to your liking. 306 | 307 | If you are using symlink/GNU stow setup, set this variable point to the .git folder 308 | within your dotfile directory. 309 | 310 | ```sh 311 | # Default value 312 | export DOTBARE_DIR="$HOME/.cfg" 313 | ``` 314 | 315 | ### DOTBARE_TREE 316 | 317 | This is the working tree for the git bare repository, meaning this is where the version 318 | control will take place. I don't recommend changing this one unless **ALL** of your config 319 | file is in something like \$XDG_CONFIG_HOME. If you are using symlink/GNU stow setup, 320 | set this variable to point to the folder containing all of your dotfiles. 321 | 322 | ```sh 323 | # Default value 324 | export DOTBARE_TREE="$HOME" 325 | ``` 326 | 327 | ### DOTBARE_BACKUP 328 | 329 | This variable is used to determine where to store the backup of your files. It is used 330 | mainly by `dotbare fbackup` which will back up all of your tracked dotfiles into this location. 331 | It is also used by `dotbare finit -u [URL]`, when there is checkout conflict, `dotbare` will 332 | automatically backup conflicted files to this location. 333 | 334 | ```sh 335 | # Default value 336 | export DOTBARE_BACKUP="${XDG_DATA_HOME:-$HOME/.local/share}/dotbare" 337 | ``` 338 | 339 | ### EDITOR 340 | 341 | This is probably already set in your ENV. `dotbare` uses this variable to determine 342 | which editor to use when running `dotbare fedit`. 343 | 344 | ```sh 345 | # Default value 346 | export EDITOR="vim" 347 | ``` 348 | 349 | ### DOTBARE_KEY 350 | 351 | This variable set default keybinds for fzf in `dotbare`. You could checkout a list of keybinds 352 | to set [here](https://github.com/junegunn/fzf/blob/97a725fbd0e54cbc07e4d72661ea2bd2bb7c01c1/man/man1/fzf.1#L648). 353 | 354 | ```sh 355 | # Default value 356 | export DOTBARE_KEY=" 357 | --bind=alt-a:toggle-all # toggle all selection 358 | --bind=alt-j:jump # label jump mode, sort of like vim-easymotion 359 | --bind=alt-0:top # set cursor back to top 360 | --bind=alt-s:toggle-sort # toggle sorting 361 | --bind=alt-t:toggle-preview # toggle preview 362 | " 363 | ``` 364 | 365 | ### DOTBARE_FZF_DEFAULT_OPTS 366 | 367 | Customize fzf settings for dotbare. This is useful when you want a different 368 | fzf behavior from your normal system fzf settings. 369 | 370 | ```sh 371 | # By default this variable is not set 372 | # More settings checkout fzf man page and their wiki 373 | # Example: if you want your preview window for dotbare to be bigger 374 | export DOTBARE_FZF_DEFAULT_OPTS="--preview-window=right:65%" 375 | ``` 376 | 377 | ### DOTBARE_PREVIEW 378 | 379 | This variable determines the preview command for file previews. By default, the preview is automatically determined 380 | using fall back (bat -> highlight -> coderay -> rougify -> cat). Set this variable to control the preview command if 381 | you have a specific preference or if you want extra flags/settings. Reference [here](https://github.com/kazhala/dotbare/blob/master/helper/preview.sh). 382 | 383 | ```sh 384 | # By default this value is not set, dotbare uses a fall back method to determine which command to use. 385 | # Make sure to have "{}" included when customizing it, the preview script substitute "{}" for actual filename. 386 | # Example: enable line number for cat command 387 | export DOTBARE_PREVIEW="cat -n {}" 388 | ``` 389 | 390 | ### DOTBARE_DIFF_PAGER 391 | 392 | This variable controls the diff output pager in previews like `dotbare flog`, `dotbare fadd` etc. It will read the value 393 | of `git config core.pager` to determine the pager to use. If you have a specific preference for `dotbare` or have not set 394 | the global pager in git config, you could use this variable to customize the diff preview. 395 | 396 | ```sh 397 | # By default this value uses fall back (git config core.pager -> cat) 398 | export DOTBARE_DIFF_PAGER="delta --diff-so-fancy --line-numbers" 399 | ``` 400 | 401 | ## Usage 402 | 403 | All usage and commands are documented in **[wiki](https://github.com/kazhala/dotbare/wiki/Commands)**. 404 | 405 | - [Commands](https://github.com/kazhala/dotbare/wiki/Commands) 406 | - [Completion](https://github.com/kazhala/dotbare/wiki/Completion) 407 | - [Custom Scripts and API](https://github.com/kazhala/dotbare/wiki/Custom-Scripts) 408 | - [Tips and Tricks](https://github.com/kazhala/dotbare/wiki/Tips-and-Tricks) 409 | 410 | ## Changes 411 | 412 | Latest changes are documented in [CHANGELOG](https://github.com/kazhala/dotbare/blob/master/CHANGELOG.md). 413 | 414 | ## Testing 415 | 416 | `dotbare` is unit tested using [bats](https://github.com/bats-core/bats-core). Mock tests are implemented using PATH override method. 417 | This is documented [here](https://github.com/kazhala/dotbare/blob/master/tests/README.md) for better readability and extensibility. 418 | 419 | Not all functions have 100% coverage and lots of user interaction cannot be effectively tested, please fire up issues if something went wrong. 420 | 421 | I've added AWSCodeBuild to CI/CD to build the docker image. It is mainly for my personal practice. If you are interested in what's happening in AWSCodeBuild 422 | you could checkout my cloudformation [template](https://github.com/kazhala/AWSCloudFormationStacks/blob/master/CICD_dotbare.yaml). 423 | 424 | ## Contributing 425 | 426 | Checkout out [CONTRIBUTING.md](https://github.com/kazhala/dotbare/blob/master/CONTRIBUTING.md) to see how you could contribute to `dotbare`. PRs are 427 | welcome and I'm happy to improve/extend `dotbare`'s functionality. 428 | 429 | Don't forget to leave a star :) 430 | 431 | ## Background 432 | 433 | `dotbare` was initially part of my personal scripts, I had a hard time sharing those scripts 434 | and as the number of scripts grows, I feel like is more appropriate to make a dedicated project 435 | for it. I hope you find it useful and enjoy it, thanks! 436 | 437 | ## Credit 438 | 439 | - credit to [forgit](https://github.com/wfxr/forgit) for inspiration. 440 | - credit to [fzf](https://github.com/junegunn/fzf) for fzf and the preview script from fzf.vim. 441 | - credit to [OMZ](https://github.com/ohmyzsh/ohmyzsh) for upgrading method. 442 | - credit to [this](https://www.atlassian.com/git/tutorials/dotfiles) post for step by step guide of setting up git bare repo. 443 | - credit to [this](https://www.youtube.com/watch?v=tBoLDpTWVOM&t=288s) video for introducing git bare repo. 444 | 445 | ## Demo 446 | 447 | You could find some more demo [here](https://github.com/kazhala/dotbare/issues/1) 448 | [![asciicast](https://asciinema.org/a/332231.svg)](https://asciinema.org/a/332231) 449 | -------------------------------------------------------------------------------- /buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | env: 4 | parameter-store: 5 | LOGIN_PASSWORD: /dotbare/dockerpassword 6 | LOGIN_USERNAME: /dotbare/dockerusername 7 | 8 | phases: 9 | install: 10 | commands: 11 | - echo Installing shellcheck ... 12 | - apt-get update -y 13 | - apt-get install shellcheck -y 14 | pre_build: 15 | commands: 16 | - echo Login to dockerhub 17 | - 'echo $LOGIN_PASSWORD | docker login --username $LOGIN_USERNAME --password-stdin' 18 | build: 19 | commands: 20 | - echo Checking script compliance ... 21 | - ./tests/shellcheck.sh 22 | - echo Building docker url image ... 23 | - docker image build --build-arg MIGRATE=url -t kazhala/dotbare:testurl -f tests/Dockerfile . 24 | - echo Running bats unittest ... 25 | - docker container run -i --rm --name dotbare kazhala/dotbare:testurl 26 | - echo Building docker bare image ... 27 | - docker image build --build-arg MIGRATE=bare -t kazhala/dotbare:testbare -f tests/Dockerfile . 28 | - echo Running bats unittest ... 29 | - docker container run -i --rm --name dotbare kazhala/dotbare:testbare 30 | - echo Building docker image ... 31 | - |- 32 | DOTBARE_VERSION=$(./dotbare --version | awk -F ": v" '{print $2}') 33 | - docker image build -t kazhala/dotbare:$DOTBARE_VERSION . 34 | - docker image tag kazhala/dotbare:$DOTBARE_VERSION kazhala/dotbare:latest 35 | post_build: 36 | commands: 37 | - echo Deploying docker image ... 38 | - docker image push kazhala/dotbare:latest 39 | - docker image push kazhala/dotbare:$DOTBARE_VERSION 40 | -------------------------------------------------------------------------------- /dotbare: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Main entry script for dotbare, used to route command to appropriate scripts 4 | # 5 | # @params 6 | # Globals 7 | # ${mydir}: string, directory of the executing script, used for sourcing helpers 8 | # Arguments 9 | # action_command: sub commands dotbare should run 10 | # General git command: log, status etc 11 | # dotbare specific commands: fadd | frm | fpop | freset | fcheckout | help etc 12 | # option flags: 13 | # check sub commands for available option flags 14 | 15 | mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 16 | source "${mydir}"/helper/set_variable.sh 17 | 18 | function usage() { 19 | echo -e "Usage: dotbare [-h] [-v] [COMMANDS] [OPTIONS] ... 20 | 21 | Interactively manage dotfiles with the help of fzf and git bare repository. 22 | To see all dotbare specific COMMANDS, run dotbare without any arguments. 23 | 24 | Optional arguments: 25 | -h, --help\t\tshow this help message and exit. 26 | -v, --version\t\tshow dotbare current version. 27 | -g, --git\t\tuse dotbare as a generic fuzzy git tool and operate in current git directory. 28 | 29 | Available commands: 30 | All git commands are available, treat dotbare as git. 31 | fadd \t\tstage files/directories interactively. 32 | fbackup \t\tperform backup for tracked files. 33 | fcheckout \t\tcheckout branch/files/commit interactively. 34 | fedit \t\tinteractively select files/commit and edit. 35 | fgrep \t\tgrep within tracked files. 36 | finit \t\tinitialise dotbare or migrate dotfiles to a new machine. 37 | flog \t\tmanage commits interactively. 38 | freset \t\treset(unstage) files or commit interactively. 39 | fstash \t\tmanage stash interactively. 40 | fstat \t\tinteractive menu to toggle stage/unstage. 41 | funtrack \t\tuntrack files interactively. 42 | fupgrade \t\tupdate dotbare to the latest master." 43 | } 44 | 45 | function list_dotbare_commands() { 46 | find "${mydir}"/scripts/* -type f -print0 \ 47 | | xargs -I __ -0 basename __ \ 48 | | fzf --no-multi --header='Available commands' --preview="${mydir}/dotbare {} -h" \ 49 | | xargs -I __ "${mydir}"/dotbare __ -h 50 | } 51 | 52 | function execute_dotbare() { 53 | [[ "$#" -eq 0 ]] \ 54 | && list_dotbare_commands \ 55 | && exit 0 56 | 57 | if [[ -x "${mydir}/scripts/$1" ]]; then 58 | exec "${mydir}/scripts/$1" "${@:2}" 59 | fi 60 | } 61 | 62 | # if no argument, display all possible actions 63 | if [[ "$#" -eq 0 ]]; then 64 | list_dotbare_commands 65 | exit 0 66 | fi 67 | 68 | [[ "$*" == 'add --all' ]] && \ 69 | echo 'If you intend to stage all modified file, run dotbare add -u' && \ 70 | echo "dotbare disabled add --all option as this will stage every single file in ${DOTBARE_TREE}" && \ 71 | exit 1 72 | 73 | case "$1" in 74 | --help|-h) 75 | usage 76 | exit 0 77 | ;; 78 | -v|--version) 79 | echo "Current dotbare version: ${DOTBARE_VERSION}" 80 | exit 0 81 | ;; 82 | -g|--git) 83 | if git rev-parse --is-inside-work-tree &>/dev/null; then 84 | DOTBARE_TREE=$(git rev-parse --show-toplevel) 85 | DOTBARE_DIR="${DOTBARE_TREE}/.git" 86 | shift 87 | case "$1" in 88 | fbackup|finit|fupgrade) 89 | echo "dotbare $1 is not supported when using dotbare as a generic fuzzy git tool" >&2 90 | exit 1 91 | ;; 92 | *) 93 | execute_dotbare "$@" 94 | ;; 95 | esac 96 | else 97 | echo "Not in a git directory" >&2 98 | exit 1 99 | fi 100 | ;; 101 | *) 102 | execute_dotbare "$@" 103 | ;; 104 | esac 105 | 106 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" "$@" 107 | -------------------------------------------------------------------------------- /dotbare.plugin.bash: -------------------------------------------------------------------------------- 1 | # shellcheck disable=SC2207 2 | 3 | mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | [[ :$PATH: != *:"${mydir}":* ]] && export PATH="$PATH:${mydir}" 5 | 6 | __dotbare_completion() 7 | { 8 | local IFS=$'\n' subcommands curr prev options verbose_options suggestions 9 | curr="${COMP_WORDS[$COMP_CWORD]}" 10 | prev="${COMP_WORDS[$COMP_CWORD-1]}" 11 | 12 | if [[ "$COMP_CWORD" -eq "1" ]]; then 13 | subcommands=$( 14 | "${mydir}"/dotbare -h \ 15 | | awk '{ 16 | if ($0 ~ /^ f.*/) { 17 | gsub(/^ /, "", $0) 18 | gsub(/\t\t/, " ", $0) 19 | print $0 20 | } 21 | }' 22 | ) 23 | options=$( 24 | "${mydir}"/dotbare -h \ 25 | | awk '{ 26 | if ($0 ~ /^ -.*/) { 27 | gsub(/,/, " ", $0) 28 | gsub(/^ /, "", $0) 29 | gsub(/\t\t/, " ", $0) 30 | $2="" 31 | print $0 32 | } 33 | }' 34 | ) 35 | verbose_options=$("${mydir}"/dotbare -h | awk '$0 ~ /^ -.*/ {print $2}') 36 | if [[ "${curr}" == --* ]]; then 37 | suggestions=($(compgen -W "${verbose_options}" -- "${curr}")) 38 | elif [[ "${curr}" == -* ]]; then 39 | suggestions=($(compgen -W "${options}" -- "${curr}")) 40 | else 41 | suggestions=($(compgen -W "${subcommands}" -- "${curr}")) 42 | fi 43 | 44 | elif [[ "${COMP_CWORD}" -eq 2 && "${prev}" == "-g" || "${prev}" == "--git" ]]; then 45 | subcommands=$( 46 | "${mydir}"/dotbare -h \ 47 | | awk '{ 48 | if ($0 ~ /^ f.*/) { 49 | if ($0 ~ /^ f(backup|init|upgrade).*/) { 50 | next 51 | } 52 | gsub(/^ /, "", $0) 53 | gsub(/\t\t/, " ", $0) 54 | print $0 55 | } 56 | }' 57 | ) 58 | suggestions=($(compgen -W "${subcommands}" -- "${curr}")) 59 | 60 | elif [[ "${COMP_WORDS[1]}" == "-g" || "${COMP_WORDS[1]}" == "--git" ]] && [[ "${COMP_CWORD}" -gt 2 ]]; then 61 | if [[ "${curr}" == --* && "${prev}" != "-h" && "${prev}" != "--help" ]]; then 62 | verbose_options=$( 63 | "${mydir}"/dotbare "${COMP_WORDS[2]}" -h 2> /dev/null \ 64 | | awk '{ 65 | if ($0 ~ /^ -p PATH/) { 66 | next 67 | } else if ($0 ~ /^ -u URL/) { 68 | next 69 | } else if ($0 ~ /^ -*/) { 70 | print $2 71 | } 72 | }' 73 | ) 74 | suggestions=($(compgen -W "${verbose_options}" -- "${curr}")) 75 | elif [[ "${prev}" != "-h" && "${prev}" != "--help" ]]; then 76 | options=$( 77 | "${mydir}"/dotbare "${COMP_WORDS[2]}" -h 2> /dev/null \ 78 | | awk '{ 79 | gsub(/,/, " ", $0) 80 | if ($0 ~ /^ -p PATH/) { 81 | next 82 | } else if ($0 ~ /^ -u URL/) { 83 | next 84 | } else if ($0 ~ /^ -*/) { 85 | gsub(/^ /, "", $0) 86 | gsub(/\t/, " ", $0) 87 | $2="" 88 | print $0 89 | } 90 | }' 91 | ) 92 | suggestions=($(compgen -W "${options}" -- "${curr}")) 93 | else 94 | return 95 | fi 96 | 97 | elif [[ "${COMP_WORDS[1]}" == "fbackup" ]] && [[ "${prev}" == "-p" || "${prev}" == "--path" ]]; then 98 | COMPREPLY=($(compgen -d -- "${curr}")) 99 | return 100 | elif [[ "${COMP_WORDS[1]}" == "finit" ]] && [[ "${prev}" == "-u" || "${prev}" == "--url" ]]; then 101 | return 102 | elif [[ "${curr}" == --* && "${prev}" != "-h" && "${prev}" != "--help" ]]; then 103 | verbose_options=$( 104 | "${mydir}"/dotbare "${COMP_WORDS[1]}" -h 2> /dev/null \ 105 | | awk '{ 106 | if ($0 ~ /^ -p PATH/) { 107 | print "--path" 108 | } else if ($0 ~ /^ -u URL/) { 109 | print "--url" 110 | } else if ($0 ~ /^ -c COL/) { 111 | print "--col" 112 | } else if ($0 ~ /^ -*/) { 113 | print $2 114 | } 115 | }' 116 | ) 117 | suggestions=($(compgen -W "${verbose_options}" -- "${curr}")) 118 | elif [[ "${prev}" != "-h" && "${prev}" != "--help" ]]; then 119 | options=$( 120 | "${mydir}"/dotbare "${COMP_WORDS[1]}" -h 2> /dev/null \ 121 | | awk '{ 122 | gsub(/,/, " ", $0) 123 | if ($0 ~ /^ -p PATH/) { 124 | gsub(/^ -p PATH --path PATH/, "-p", $0) 125 | gsub(/\t/, " ", $0) 126 | print $0 127 | } else if ($0 ~ /^ -u URL/) { 128 | gsub(/^ -u URL --url URL/, "-u", $0) 129 | gsub(/\t/, " ", $0) 130 | print $0 131 | } else if ($0 ~ /^ -c COL/) { 132 | gsub(/^ -c COL --col COL/, "-c", $0) 133 | gsub(/\t/, " ", $0) 134 | print $0 135 | } else if ($0 ~ /^ -*/) { 136 | gsub(/^ /, "", $0) 137 | gsub(/\t/, " ", $0) 138 | $2="" 139 | print $0 140 | } 141 | }' 142 | ) 143 | suggestions=($(compgen -W "${options}" -- "${curr}")) 144 | fi 145 | 146 | if [[ "${#suggestions[*]}" -eq 1 ]]; then 147 | COMPREPLY=("${suggestions[@]%% *}") 148 | else 149 | for i in "${!suggestions[@]}"; do 150 | suggestions[$i]="$(printf '%*s' "-$COLUMNS" "${suggestions[$i]}")" 151 | done 152 | COMPREPLY=("${suggestions[@]}") 153 | fi 154 | } 155 | 156 | _dotbare_completion_cmd() { 157 | local complete_name="${1:-dotbare}" 158 | complete -F __dotbare_completion "${complete_name}" 159 | } 160 | 161 | _dotbare_completion_git() { 162 | local complete_name="${1:-dotbare}" 163 | complete -F _git "${complete_name}" 164 | } 165 | -------------------------------------------------------------------------------- /dotbare.plugin.zsh: -------------------------------------------------------------------------------- 1 | 0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}" 2 | _path="${0:h}" 3 | 4 | if [[ -z "${path[(r)$_path]}" ]]; then 5 | path+=( "${_path}" ) 6 | fi 7 | 8 | __dotbare_completion() { 9 | local context state state_descr line ret curcontext 10 | local -A opt_args 11 | ret=1 12 | curcontext="${curcontext}" 13 | 14 | _arguments -C \ 15 | '(- : *)'{-h,--help}'[show help information]' \ 16 | '(- : *)'{-v,--version}'[display dotbare version]' \ 17 | '(-g --git)'{-g,--git}'[use dotbare as a generic fuzzy git tool and operate in current git directory]' \ 18 | '1:cmds:->cmds' \ 19 | '*::options:->options' \ 20 | && ret=0 21 | 22 | case "${state}" in 23 | cmds) 24 | local subcommands 25 | subcommands=( 26 | 'fadd:stage files' 27 | 'fbackup:backup files' 28 | 'fcheckout:checkout file/branch/commit' 29 | 'fedit:edit files' 30 | 'fgrep:grep within tracked files' 31 | 'finit:init/migrate dotbare' 32 | 'flog:interactive log viewer' 33 | 'freset:reset files/commit' 34 | 'fstash:stage management' 35 | 'fstat:toggle stage/unstage of files' 36 | 'funtrack:untrack files' 37 | 'fupgrade:update dotbare' 38 | ) 39 | _describe 'command' subcommands \ 40 | && ret=0 41 | ;; 42 | options) 43 | case "${line[1]}" in 44 | fadd) 45 | _arguments \ 46 | '(- : *)'{-h,--help}'[show help information]' \ 47 | '(-f --file -d --dir -h --help)'{-f,--file}'[select files from PWD and stage]' \ 48 | '(-d --dir -f --file -h --help)'{-d,--dir}'[select directory from PWD and stage]' \ 49 | && ret=0 50 | ;; 51 | fbackup) 52 | _arguments \ 53 | '(- : *)'{-h,--help}'[show help information]' \ 54 | '(-s --select -p --path -h --help)'{-s,--select}'[select tracked files to backup]' \ 55 | '(-p --path -s --select -h --help)'{-p,--path}'[sepcify path of files to backup]:filename:_files' \ 56 | '(-m --move -h --help)'{-m,--move}'[use mv cmd instead of cp cmd]' \ 57 | && ret=0 58 | ;; 59 | fcheckout) 60 | _arguments \ 61 | '(- : *)'{-h,--help}'[show help information]' \ 62 | '(-s --select -b --branch -c --commit -h --help)'{-s,--select}'[select files and then checkout them in selected commits]' \ 63 | '(-b --branch -s --select -c --commit -h --help)'{-b,--branch}'[checkout branch]' \ 64 | '(-c --commit -b --branch -s --select -h --help)'{-c,--commit}'[checkout commit]' \ 65 | '(-y --yes -h --help)'{-y,--yes}'[acknowledge all actions and skip confirmation]' \ 66 | && ret=0 67 | ;; 68 | fedit) 69 | _arguments \ 70 | '(- : *)'{-h,--help}'[show help information]' \ 71 | '(-m --modified -c --commit -h --help)'{-m,--modified}'[edit modified files]' \ 72 | '(-c --commit -m --modified -h --help)'{-c,--commit}'[edit commits]' \ 73 | && ret=0 74 | ;; 75 | fgrep) 76 | _arguments \ 77 | '(- : *)'{-h,--help}'[show help information]' \ 78 | '(-f --full -c --col)'{-f,--full}'[include all columns during fzf search, as if using "--col 1"]' \ 79 | '(-f --full -c --col)'{-c,--col}'[specify a column number to start searching in fzf]: :->cols' \ 80 | && ret=0 81 | ;; 82 | finit) 83 | _arguments \ 84 | '(- : *)'{-h,--help}'[show help information]' \ 85 | '(-u --url -h --help)'{-u,--url}'[migrate remote dotfiles to current system]: :->url' \ 86 | '(-s --submodule -h --help)'{-s,--submodule}'[clone submodules during migration]' \ 87 | '(-y --yes -h --help)'{-y,--yes}'[acknowledge all actions and skip confirmation]' \ 88 | && ret=0 89 | ;; 90 | flog) 91 | _arguments \ 92 | '(- : *)'{-h,--help}'[show help information]' \ 93 | '(-r --revert -R --reset -e --edit -c --checkout -h --help)'{-r,--revert}'[revert the selected commit and skip action menu]' \ 94 | '(-r --revert -R --reset -e --edit -c --checkout -h --help)'{-R,--reset}'[reset the selected commit and skip action menu]' \ 95 | '(-r --revert -R --reset -e --edit -c --checkout -h --help)'{-e,--edit}'[edit the selected commit and skip action menu]' \ 96 | '(-r --revert -R --reset -e --edit -c --checkout -h --help)'{-c,--checkout}'[checkout the selected commit and skip action menu]' \ 97 | '(-y --yes -h --help)'{-y,--yes}'[acknowledge all actions and skip confirmation]' \ 98 | && ret=0 99 | ;; 100 | freset) 101 | _arguments \ 102 | '(- : *)'{-h,--help}'[show help information]' \ 103 | '(-c --commit -h --help)'{-c,--commit}'[reset HEAD to certain commit]' \ 104 | '(-S --soft -H --hard -h --help)'{-S,--soft}'[reset commit using --soft flag]' \ 105 | '(-H --hard -S --soft -h --help)'{-H,--hard}'[reset commit using --hard flag]' \ 106 | '(-y --yes -h --help)'{-y,--yes}'[acknowledge all actions and skip confirmation]' \ 107 | && ret=0 108 | ;; 109 | fstash) 110 | _arguments \ 111 | '(- : *)'{-h,--help}'[show help information]' \ 112 | '(-s --select -d --delete -p --pop -h --help)'{-s,--select}'[list modified files and stash the selected files]' \ 113 | '(-s --select -d --delete -p --pop -h --help)'{-d,--delete}'[list stash and delete the selected stash]' \ 114 | '(-s --select -d --delete -p --pop -h --help)'{-p,--pop}'[use "stash pop" instead of "stash apply"]' \ 115 | && ret=0 116 | ;; 117 | fstat) 118 | _arguments \ 119 | '(- : *)'{-h,--help}'[show help information]' \ 120 | && ret=0 121 | ;; 122 | funtrack) 123 | _arguments \ 124 | '(- : *)'{-h,--help}'[show help information]' \ 125 | '(-t --temp -r --resume -h --help)'{-t,--temp}'[temporarily ignore changes of the selected files]' \ 126 | '(-t --temp -r --resume -h --help)'{-r,--resume}'[resume tracking changes of the selected files]' \ 127 | '(-y --yes -h --help)'{-y,--yes}'[acknowledge all actions and skip confirmation]' \ 128 | && ret=0 129 | ;; 130 | fupgrade) 131 | _arguments \ 132 | '(- : *)'{-h,--help}'[show help information]' \ 133 | && ret=0 134 | ;; 135 | esac 136 | ;; 137 | esac 138 | 139 | return "${ret}"; 140 | } 141 | 142 | _dotbare_completion_cmd() { 143 | local compdef_name="dotbare" 144 | compdef __dotbare_completion "${compdef_name}" 145 | } 146 | 147 | _dotbare_completion_git() { 148 | local compdef_name="dotbare" 149 | compdef "${compdef_name}"=git 150 | } 151 | 152 | _widget_dotbare_fadd() { dotbare fadd; } 153 | _widget_dotbare_fedit() { dotbare fedit; } 154 | _widget_dotbare_fcheckout() { dotbare fcheckout; } 155 | _widget_dotbare_freset() { dotbare freset; } 156 | _widget_dotbare_flog() { dotbare flog; } 157 | _widget_dotbare_fgrep() { dotbare fgrep; } 158 | _widget_dotbare_fstat() { dotbare fstat; } 159 | 160 | zle -N dotbare-fadd _widget_dotbare_fadd 161 | zle -N dotbare-fedit _widget_dotbare_fedit 162 | zle -N dotbare-fcheckout _widget_dotbare_fcheckout 163 | zle -N dotbare-freset _widget_dotbare_reset 164 | zle -N dotbare-flog _widget_dotbare_flog 165 | zle -N dotbare-fgrep _widget_dotbare_fgrep 166 | zle -N dotbare-fstat _widget_dotbare_fstat 167 | 168 | _widget_git_transform_dotbare() { 169 | local dotbare_cmd new_cmd 170 | dotbare_cmd=$(alias | grep dotbare | cut -d'=' -f1 | head -n 1) 171 | [[ -z "${dotbare_cmd}" ]] && dotbare_cmd="dotbare" 172 | dotbare_cmd="${dotbare_cmd} -g" 173 | BUFFER=$(echo "$BUFFER" \ 174 | | awk -v dotbare="${dotbare_cmd}" '{ 175 | if ($1 == "git") { 176 | $1=dotbare 177 | if ($2 ~ /(log|add|reset|checkout|status|stash|grep|untrack|stat)/) { 178 | if ($2 == "status"){ 179 | $2="stat" 180 | } 181 | $2="f"$2 182 | } 183 | } 184 | print $0 185 | }' 186 | ) 187 | zle end-of-line 188 | } 189 | 190 | zle -N dotbare-transform _widget_git_transform_dotbare 191 | -------------------------------------------------------------------------------- /helper/get_confirmation.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # confirmaiton helper 4 | 5 | ####################################### 6 | # Helper function to get user confirmation 7 | # Globals: 8 | # None 9 | # Locals: 10 | # ${confirm}: user confirmation status 11 | # Arguments: 12 | # $1: confirmation message to show during confirm 13 | # Outputs: 14 | # ${confirm}: y or n indicating user response 15 | ####################################### 16 | function get_confirmation() { 17 | local confirm 18 | local message="${1:-Confirm?}" 19 | while [ "${confirm}" != 'y' ] && [ "${confirm}" != 'n' ]; do 20 | read -r -p "${message}(y/n): " confirm 21 | done 22 | echo "${confirm}" 23 | } 24 | -------------------------------------------------------------------------------- /helper/git_query.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # helper functions to obtain git related information 4 | 5 | ####################################### 6 | # let user select a commit interactively 7 | # credit to forgit for the git log format 8 | # Arguments: 9 | # $1: the helper message to display in the fzf header 10 | # $2: files to show diff against HEAD 11 | # Outputs: 12 | # the selected commit 6 char code 13 | # e.g. b60b330 14 | ####################################### 15 | # TODO: line33 "${files[*]}" cannot handle space in file names, but "${files[@]}" won't get properly 16 | # processed by git for whatever reason just in this preview situation but works every where else, HELP needed. 17 | # although this won't affect any real functionality or break the code, it will just print a error message in preview. 18 | function get_commit() { 19 | local header="${1:-select a commit}" 20 | local files=("${@:2}") 21 | if [[ "${#files[@]}" -eq 0 ]]; then 22 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" \ 23 | log --color=always --format='%C(auto)%h%d %s %C(black)%C(bold)%cr' \ 24 | | fzf --header="${header}" --no-multi \ 25 | --preview "echo {} \ 26 | | awk '{print \$1}' \ 27 | | xargs -I __ git --git-dir=${DOTBARE_DIR} --work-tree=${DOTBARE_TREE} \ 28 | show --color=always __ \ 29 | | ${DOTBARE_DIFF_PAGER}" \ 30 | | awk '{print $1}' 31 | else 32 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" \ 33 | log --oneline --color=always --decorate=short \ 34 | | fzf --header="${header}" --no-multi --preview "echo {} \ 35 | | awk '{print \$1}' \ 36 | | xargs -I __ git --git-dir=${DOTBARE_DIR} --work-tree=${DOTBARE_TREE} \ 37 | diff --color=always __ ${files[*]} \ 38 | | ${DOTBARE_DIFF_PAGER}" \ 39 | | awk '{print $1}' 40 | fi 41 | } 42 | 43 | ####################################### 44 | # let user select a branch interactively 45 | # Arguments: 46 | # $1: the helper message to display in the fzf header 47 | # Outputs: 48 | # the selected branch name 49 | # e.g. master 50 | ####################################### 51 | function get_branch() { 52 | local header="${1:-select a branch}" 53 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" branch -a \ 54 | | awk '{ 55 | if ($0 ~ /\*.*\(HEAD.*/) { 56 | gsub(/\* /, "", $0) 57 | print "\033[32m" $0 "\033[0m" 58 | } else if (match($1, "\\*") != 0) { 59 | print "\033[32m" $2 "\033[0m" 60 | } else if ($0 ~ /^[ \t]+remotes\/.*/) { 61 | gsub(/[ \t]+/, "", $0) 62 | print "\033[31m" $0 "\033[0m" 63 | } else { 64 | gsub(/^[ \t]+/, "", $0) 65 | print $0 66 | } 67 | }' \ 68 | | fzf --no-multi --header="${header}" \ 69 | --preview="echo {} \ 70 | | awk '{ 71 | if (\$0 ~ /.*HEAD.*/) { 72 | print \"HEAD\" 73 | } else { 74 | print \$0 75 | } 76 | }' \ 77 | | xargs -I __ git --git-dir=${DOTBARE_DIR} --work-tree=${DOTBARE_TREE} \ 78 | log --color=always --color=always --format='%C(auto)%h%d %s %C(black)%C(bold)%cr' __" 79 | } 80 | 81 | ####################################### 82 | # let user select a dotbare tracked file interactively 83 | # Arguments: 84 | # $1: the helper message to display in the fzf header 85 | # $2: print option, values (full|raw) 86 | # $3: if exist, don't do multi selection, do single 87 | # Outputs: 88 | # the selected file path 89 | # e.g.$HOME/.config/nvim/init.vim 90 | ####################################### 91 | function get_git_file() { 92 | local mydir 93 | local header="${1:-select tracked file}" 94 | local print_opt="${2:-full}" 95 | mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 96 | set_fzf_multi "$3" 97 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" \ 98 | ls-files --full-name --directory "${DOTBARE_TREE}" \ 99 | | fzf --header="${header}" \ 100 | --preview "${mydir}/../helper/preview.sh ${DOTBARE_TREE}/{}" \ 101 | | awk -v home="${DOTBARE_TREE}" -v print_opt="${print_opt}" '{ 102 | if (print_opt == "full") { 103 | print home "/" $0 104 | } else { 105 | print $0 106 | } 107 | }' 108 | } 109 | 110 | ####################################### 111 | # let user select a modified file interactively 112 | # Arguments: 113 | # $1: the helper message to display in the fzf header 114 | # $2: display mode of modified files. 115 | # default: true 116 | # all: display all modified, include staged and unstaged 117 | # staged: display only staged files 118 | # unstaged: display only unstaged files 119 | # $3: output_format 120 | # default: name 121 | # name: formatted name of the file 122 | # raw: raw file name with status 123 | # $4: if exists, don't do multi selection, do single 124 | # Outputs: 125 | # the selected file path 126 | # e.g.$HOME/.config/nvim/init.vim 127 | ####################################### 128 | function get_modified_file() { 129 | local header="${1:-select a modified file}" 130 | local display_mode="${2:-all}" 131 | local output_format="${3:-name}" 132 | set_fzf_multi "$4" 133 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" \ 134 | status --porcelain \ 135 | | awk -v display_mode="${display_mode}" '{ 136 | if ($0 ~ /^[A-Za-z][A-Za-z].*$/) { 137 | print "\033[32m" substr($0, 1, 1) "\033[31m" substr($0, 2) "\033[0m" 138 | } else if ($0 ~ /^[A-Za-z][ \t].*$/) { 139 | if (display_mode == "all" || display_mode == "staged") { 140 | print "\033[32m" $0 "\033[0m" 141 | } 142 | } else { 143 | if (display_mode == "all" || display_mode == "unstaged") { 144 | print "\033[31m" $0 "\033[0m" 145 | } 146 | } 147 | }' \ 148 | | fzf --header="${header}" --preview "echo {} \ 149 | | awk '{sub(\$1 FS,\"\");print \$0}' \ 150 | | xargs -I __ git --git-dir=${DOTBARE_DIR} --work-tree=${DOTBARE_TREE} \ 151 | diff HEAD --color=always -- ${DOTBARE_TREE}/__ \ 152 | | ${DOTBARE_DIFF_PAGER}" \ 153 | | awk -v home="${DOTBARE_TREE}" -v format="${output_format}" '{ 154 | if (format == "name") { 155 | $1="" 156 | gsub(/^[ \t]/, "", $0) 157 | gsub(/"/, "", $0) 158 | print home "/" $0 159 | } else { 160 | print $0 161 | } 162 | }' 163 | } 164 | 165 | ####################################### 166 | # let user select a stash interactively 167 | # Arguments: 168 | # $1: the help message to display in header 169 | # $2: if exists, don't do multi select, only allow single selection 170 | # Outputs: 171 | # the selected stash identifier 172 | # e.g. stash@{0} 173 | ####################################### 174 | function get_stash() { 175 | local header="${1:-select a stash}" 176 | set_fzf_multi "$2" 177 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" \ 178 | stash list \ 179 | | fzf --header="${header}" --preview "echo {} \ 180 | | awk '{ 181 | gsub(/:/, \"\", \$1) 182 | print \$1 183 | }' \ 184 | | xargs -I __ git --git-dir=${DOTBARE_DIR} --work-tree=${DOTBARE_TREE} \ 185 | stash show -p __ --color=always \ 186 | | ${DOTBARE_DIFF_PAGER}" \ 187 | | awk '{ 188 | gsub(/:/, "", $1) 189 | print $1 190 | }' 191 | } 192 | 193 | ####################################### 194 | # Using git grep to find word within 195 | # all tracked files in the bare repo. 196 | # Arguments: 197 | # $1: the help message to display in header 198 | # $2: the fzf delimiter to start searching, default is 3 199 | # $3: if exists, don't do multi select, only allow single selection 200 | # Outputs: 201 | # the selected file name with it's line number and line, separated by ":" 202 | # e.g. .bash_profile:1:echo hello 203 | ####################################### 204 | function grep_words() { 205 | local header="${1:-select matches to edit}" 206 | local delimiter="${2:-3}" 207 | set_fzf_multi "$2" 208 | cd "${DOTBARE_TREE}" || exit 209 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" \ 210 | grep --line-number -- . \ 211 | | fzf --delimiter : --nth "${delimiter}".. --header="${header}" \ 212 | --preview "${mydir}/../helper/preview.sh ${DOTBARE_TREE}/{}" \ 213 | | awk -F ":" -v home="${DOTBARE_TREE}" '{ 214 | print home "/" $1 ":" $2 215 | }' 216 | } 217 | -------------------------------------------------------------------------------- /helper/preview.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # dynamic preview command for dotbare 4 | # borrowed and modified from fzf.vim 5 | # 6 | # @params 7 | # Globals 8 | # reverse_seq: reverse highlight sequence for easier print 9 | # reset_seq: reset highlight sequence for eaiser print 10 | # input_option: the array containing informaiton from cmd argument 11 | # preview_file: the file path to be previewed 12 | # preview_center: the center/highlight line of the preview, if not set, display entire file 13 | # preview_lines: total lines to be previed, used to determine the first line and last line to be printed 14 | # preview_first: the first line number of the file to be printed 15 | # preview_last: the last line number of the file to be printed 16 | # file_mime: mime of the file, used to display information for binary file 17 | # Arguments 18 | # $1: The filename and line info to be previewed 19 | # Format: filepath[:lineno][:ignored] 20 | # Example 21 | # preview "$HOME/.bashrc:15" 22 | 23 | ####################################### 24 | # display the preview of the file 25 | # construct argument for the action, execute and exit 26 | # Arguments: 27 | # $1: the file path to be previewed 28 | # $2: the first line number to be previewd, optional 29 | # $3: the center/highlight line in the preview, optional 30 | # $4: the last line number to be previewed, optional 31 | # Note: 32 | # if the line number information such as $2 $3 $4 is not given, the entire 33 | # file will be printed. 34 | # Otherwise only the $2-$4 parts of the file will be printed and $3 will be highlighted 35 | ####################################### 36 | function display_preview() { 37 | local fallback_cmd preview_cmd preview_file preview_first preview_last preview_center 38 | preview_file="$1" 39 | preview_first="$2" 40 | preview_center="$3" 41 | preview_last="$4" 42 | fallback_cmd="highlight -O ansi -l {} || coderay {} || rougify {} || cat {}" 43 | preview_cmd=${DOTBARE_PREVIEW:-${fallback_cmd}} 44 | preview_cmd=${preview_cmd//{\}/$(printf %q "${preview_file}")} 45 | 46 | if [[ -z "${preview_first}" ]] || [[ -z "${preview_center}" ]] || [[ -z "${preview_last}" ]]; then 47 | if [[ -z "${DOTBARE_PREVIEW}" ]] && command -v bat > /dev/null; then 48 | bat --color=always --pager=never "${preview_file}" 49 | exit $? 50 | fi 51 | eval "${preview_cmd}" 2> /dev/null 52 | exit 0 53 | else 54 | if [ -z "${DOTBARE_PREVIEW}" ] && command -v bat > /dev/null; then 55 | bat --color=always --pager=never \ 56 | --line-range="${preview_first}":"${preview_last}" --highlight-line="${preview_center}" "${preview_file}" 57 | exit $? 58 | fi 59 | eval "${preview_cmd}" 2> /dev/null \ 60 | | awk "NR >= ${preview_first} && NR <= ${preview_last} { \ 61 | if (NR == ${preview_center}) \ 62 | { gsub(/\x1b[[0-9;]*m/, \"&${reverse_seq}\"); printf(\"${reverse_seq}%s\n${reset_seq}\", \$0); } \ 63 | else \ 64 | printf(\"${reset_seq}%s\n\", \$0); \ 65 | }" 66 | exit 0 67 | fi 68 | } 69 | 70 | reverse_seq="\x1b[7m" 71 | reset_seq="\x1b[m" 72 | 73 | IFS=':' read -r -a input_option <<< "$1" 74 | preview_file=${input_option[0]} 75 | preview_center=${input_option[1]} 76 | 77 | # potential fix for windows? Although I don't think dotbare will be usable in windows yet 78 | if [[ $1 =~ ^[A-Z]:\\ ]]; then 79 | preview_file=$preview_file:${input_option[1]} 80 | preview_center=${input_option[2]} 81 | fi 82 | 83 | preview_file="${preview_file/#\~\//$HOME/}" 84 | if [ ! -r "${preview_file}" ]; then 85 | echo "File not found ${preview_file}" 86 | exit 1 87 | fi 88 | 89 | # if binary, display binary info and exit 90 | file_mime=$(file --dereference --mime "${preview_file}") 91 | [[ "${file_mime}" =~ binary ]] \ 92 | && echo "${file_mime}" \ 93 | && exit 0 94 | 95 | # if no line number was given, just preview the entire file 96 | [[ -z "${preview_center}" ]] && display_preview "${preview_file}" 97 | 98 | # if invalid line number was given, just preview the entire file 99 | [[ -n "${preview_center}" && ! "${preview_center}" =~ ^[0-9] ]] && display_preview "${preview_file}" 100 | 101 | # get the size of the termianl window and determine the first line and last line 102 | preview_center=${preview_center/[^0-9]*/} 103 | 104 | if [ -n "${FZF_PREVIEW_LINES}" ]; then 105 | preview_lines="${FZF_PREVIEW_LINES}" 106 | else 107 | if [ -r /dev/tty ]; then 108 | preview_lines=$(stty size < /dev/tty | awk '{print $1}') 109 | else 110 | preview_lines=40 111 | fi 112 | fi 113 | 114 | preview_first=$((preview_center-preview_lines/3)) 115 | preview_first=$((preview_first < 1 ? 1 : preview_first)) 116 | preview_last=$((preview_first+preview_lines-1)) 117 | 118 | display_preview "${preview_file}" "${preview_first}" "${preview_center}" "${preview_last}" 119 | -------------------------------------------------------------------------------- /helper/search_file.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # search local file or directory taking consideration of optional dependency 4 | 5 | ####################################### 6 | # search local file 7 | # Arguments: 8 | # $1: string, f or d, search file or directory 9 | # Outputs: 10 | # A user selected file path 11 | ####################################### 12 | function search_file() { 13 | local search_type="$1" mydir 14 | mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 15 | if [[ "${search_type}" == "f" ]]; then 16 | find . -maxdepth 1 -type f | sed "s|\./||g" | fzf --multi --preview "${mydir}/preview.sh {}" 17 | elif [[ "${search_type}" == "d" ]]; then 18 | if command -v tree &>/dev/null; then 19 | find . -maxdepth 1 -type d | awk '{if ($0 != "." && $0 != "./.git"){gsub(/^\.\//, "", $0);print $0}}' | fzf --multi --preview "tree -L 1 -C --dirsfirst {}" 20 | else 21 | find . -maxdepth 1 -type d | awk '{if ($0 != "." && $0 != "./.git"){gsub(/^\.\//, "", $0);print $0}}' | fzf --multi 22 | fi 23 | fi 24 | } 25 | -------------------------------------------------------------------------------- /helper/set_variable.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # check env variables and set default variables 4 | # 5 | # @params 6 | # Globals 7 | # ${DOTBARE_DIR}: location of the bare repo 8 | # ${DOTBARE_TREE}: which folder is the bare repo tracking 9 | # ${DOTBARE_BACKUP}: backup directory for all tracked files 10 | # ${DOTBARE_KEY}: default key bindings 11 | # ${FZF_DEFAULT_OPTS}: update FZF_DEFAULT_OPTS to reflect dotbare changes 12 | # ${DOTBARE_FZF_DEFAULT_OPTS}: user custom setting for dotbare 13 | # ${EDITOR}: default editor to use 14 | 15 | export DOTBARE_DIR="${DOTBARE_DIR:-$HOME/.cfg/}" 16 | export DOTBARE_TREE="${DOTBARE_TREE:-$HOME}" 17 | export DOTBARE_BACKUP="${DOTBARE_BACKUP:-${XDG_DATA_HOME:-$HOME/.local/share}/dotbare}" 18 | export DOTBARE_VERSION="v1.3.1" 19 | 20 | export DOTBARE_DIFF_PAGER="${DOTBARE_DIFF_PAGER:-$(git config core.pager || echo 'cat')}" 21 | 22 | export EDITOR="${EDITOR:-vim}" 23 | if [[ -z "${DOTBARE_KEY}" ]]; then 24 | DOTBARE_KEY=" 25 | --bind=alt-a:toggle-all 26 | --bind=alt-w:jump 27 | --bind=alt-0:top 28 | --bind=alt-s:toggle-sort 29 | --bind=alt-t:toggle-preview 30 | " 31 | fi 32 | 33 | [[ -z "${FZF_DEFAULT_OPTS}" ]] && export FZF_DEFAULT_OPTS='--cycle' 34 | 35 | FZF_DEFAULT_OPTS=" 36 | $FZF_DEFAULT_OPTS 37 | --ansi 38 | --cycle 39 | --exit-0 40 | $DOTBARE_FZF_DEFAULT_OPTS 41 | $DOTBARE_KEY 42 | " 43 | 44 | [[ -z "${COLUMNS}" ]] \ 45 | && COLUMNS=$(stty size < /dev/tty | cut -d' ' -f2) 46 | [[ "${COLUMNS}" -lt 80 ]] \ 47 | && FZF_DEFAULT_OPTS="$FZF_DEFAULT_OPTS --preview-window=hidden" 48 | 49 | ####################################### 50 | # determine to set multi selection or not 51 | # Globals: 52 | # ${FZF_DEFAULT_OPTS}: fzf options 53 | # Arguments: 54 | # $1: if exists, disable multi, set single 55 | ####################################### 56 | function set_fzf_multi() { 57 | local no_multi="$1" 58 | if [[ -z "${no_multi}" ]]; then 59 | export FZF_DEFAULT_OPTS="${FZF_DEFAULT_OPTS} --multi" 60 | else 61 | export FZF_DEFAULT_OPTS="${FZF_DEFAULT_OPTS} --no-multi" 62 | fi 63 | } 64 | -------------------------------------------------------------------------------- /pkg/completion/bash/dotbare: -------------------------------------------------------------------------------- 1 | # shellcheck disable=SC2207 2 | 3 | _dotbare_completion() 4 | { 5 | local IFS=$'\n' subcommands curr prev options verbose_options suggestions 6 | curr="${COMP_WORDS[$COMP_CWORD]}" 7 | prev="${COMP_WORDS[$COMP_CWORD-1]}" 8 | 9 | if [[ "$COMP_CWORD" -eq "1" ]]; then 10 | subcommands=$( 11 | dotbare -h \ 12 | | awk '{ 13 | if ($0 ~ /^ f.*/) { 14 | gsub(/^ /, "", $0) 15 | gsub(/\t\t/, " ", $0) 16 | print $0 17 | } 18 | }' 19 | ) 20 | options=$( 21 | dotbare -h \ 22 | | awk '{ 23 | if ($0 ~ /^ -.*/) { 24 | gsub(/,/, " ", $0) 25 | gsub(/^ /, "", $0) 26 | gsub(/\t\t/, " ", $0) 27 | $2="" 28 | print $0 29 | } 30 | }' 31 | ) 32 | verbose_options=$(dotbare -h | awk '$0 ~ /^ -.*/ {print $2}') 33 | if [[ "${curr}" == --* ]]; then 34 | suggestions=($(compgen -W "${verbose_options}" -- "${curr}")) 35 | elif [[ "${curr}" == -* ]]; then 36 | suggestions=($(compgen -W "${options}" -- "${curr}")) 37 | else 38 | suggestions=($(compgen -W "${subcommands}" -- "${curr}")) 39 | fi 40 | 41 | elif [[ "${COMP_CWORD}" -eq 2 && "${prev}" == "-g" || "${prev}" == "--git" ]]; then 42 | subcommands=$( 43 | dotbare -h \ 44 | | awk '{ 45 | if ($0 ~ /^ f.*/) { 46 | if ($0 ~ /^ f(backup|init|upgrade).*/) { 47 | next 48 | } 49 | gsub(/^ /, "", $0) 50 | gsub(/\t\t/, " ", $0) 51 | print $0 52 | } 53 | }' 54 | ) 55 | suggestions=($(compgen -W "${subcommands}" -- "${curr}")) 56 | 57 | elif [[ "${COMP_WORDS[1]}" == "-g" || "${COMP_WORDS[1]}" == "--git" ]] && [[ "${COMP_CWORD}" -gt 2 ]]; then 58 | if [[ "${curr}" == --* && "${prev}" != "-h" && "${prev}" != "--help" ]]; then 59 | verbose_options=$( 60 | dotbare "${COMP_WORDS[2]}" -h 2> /dev/null \ 61 | | awk '{ 62 | if ($0 ~ /^ -p PATH/) { 63 | next 64 | } else if ($0 ~ /^ -u URL/) { 65 | next 66 | } else if ($0 ~ /^ -*/) { 67 | print $2 68 | } 69 | }' 70 | ) 71 | suggestions=($(compgen -W "${verbose_options}" -- "${curr}")) 72 | elif [[ "${prev}" != "-h" && "${prev}" != "--help" ]]; then 73 | options=$( 74 | dotbare "${COMP_WORDS[2]}" -h 2> /dev/null \ 75 | | awk '{ 76 | gsub(/,/, " ", $0) 77 | if ($0 ~ /^ -p PATH/) { 78 | next 79 | } else if ($0 ~ /^ -u URL/) { 80 | next 81 | } else if ($0 ~ /^ -*/) { 82 | gsub(/^ /, "", $0) 83 | gsub(/\t/, " ", $0) 84 | $2="" 85 | print $0 86 | } 87 | }' 88 | ) 89 | suggestions=($(compgen -W "${options}" -- "${curr}")) 90 | else 91 | return 92 | fi 93 | 94 | elif [[ "${COMP_WORDS[1]}" == "fbackup" ]] && [[ "${prev}" == "-p" || "${prev}" == "--path" ]]; then 95 | COMPREPLY=($(compgen -d -- "${curr}")) 96 | return 97 | elif [[ "${COMP_WORDS[1]}" == "finit" ]] && [[ "${prev}" == "-u" || "${prev}" == "--url" ]]; then 98 | return 99 | elif [[ "${curr}" == --* && "${prev}" != "-h" && "${prev}" != "--help" ]]; then 100 | verbose_options=$( 101 | dotbare "${COMP_WORDS[1]}" -h 2> /dev/null \ 102 | | awk '{ 103 | if ($0 ~ /^ -p PATH/) { 104 | print "--path" 105 | } else if ($0 ~ /^ -u URL/) { 106 | print "--url" 107 | } else if ($0 ~ /^ -c COL/) { 108 | print "--col" 109 | } else if ($0 ~ /^ -*/) { 110 | print $2 111 | } 112 | }' 113 | ) 114 | suggestions=($(compgen -W "${verbose_options}" -- "${curr}")) 115 | elif [[ "${prev}" != "-h" && "${prev}" != "--help" ]]; then 116 | options=$( 117 | dotbare "${COMP_WORDS[1]}" -h 2> /dev/null \ 118 | | awk '{ 119 | gsub(/,/, " ", $0) 120 | if ($0 ~ /^ -p PATH/) { 121 | gsub(/^ -p PATH --path PATH/, "-p", $0) 122 | gsub(/\t/, " ", $0) 123 | print $0 124 | } else if ($0 ~ /^ -u URL/) { 125 | gsub(/^ -u URL --url URL/, "-u", $0) 126 | gsub(/\t/, " ", $0) 127 | print $0 128 | } else if ($0 ~ /^ -c COL/) { 129 | gsub(/^ -c COL --col COL/, "-c", $0) 130 | gsub(/\t/, " ", $0) 131 | print $0 132 | } else if ($0 ~ /^ -*/) { 133 | gsub(/^ /, "", $0) 134 | gsub(/\t/, " ", $0) 135 | $2="" 136 | print $0 137 | } 138 | }' 139 | ) 140 | suggestions=($(compgen -W "${options}" -- "${curr}")) 141 | fi 142 | 143 | if [[ "${#suggestions[*]}" -eq 1 ]]; then 144 | COMPREPLY=("${suggestions[@]%% *}") 145 | else 146 | for i in "${!suggestions[@]}"; do 147 | suggestions[$i]="$(printf '%*s' "-$COLUMNS" "${suggestions[$i]}")" 148 | done 149 | COMPREPLY=("${suggestions[@]}") 150 | fi 151 | } 152 | 153 | complete -F _dotbare_completion dotbare 154 | -------------------------------------------------------------------------------- /pkg/completion/zsh/_dotbare: -------------------------------------------------------------------------------- 1 | #compdef dotbare 2 | 3 | _dotbare() { 4 | local context state state_descr line ret curcontext 5 | local -A opt_args 6 | ret=1 7 | curcontext="${curcontext}" 8 | 9 | _arguments -C \ 10 | '(- : *)'{-h,--help}'[show help information]' \ 11 | '(- : *)'{-v,--version}'[display dotbare version]' \ 12 | '(-g --git)'{-g,--git}'[use dotbare as a generic fuzzy git tool and operate in current git directory]' \ 13 | '1:cmds:->cmds' \ 14 | '*::options:->options' \ 15 | && ret=0 16 | 17 | case "${state}" in 18 | cmds) 19 | local subcommands 20 | subcommands=( 21 | 'fadd:stage files' 22 | 'fbackup:backup files' 23 | 'fcheckout:checkout file/branch/commit' 24 | 'fedit:edit files' 25 | 'fgrep:grep within tracked files' 26 | 'finit:init/migrate dotbare' 27 | 'flog:interactive log viewer' 28 | 'freset:reset files/commit' 29 | 'fstash:stage management' 30 | 'fstat:toggle stage/unstage of files' 31 | 'funtrack:untrack files' 32 | 'fupgrade:update dotbare' 33 | ) 34 | _describe 'command' subcommands \ 35 | && ret=0 36 | ;; 37 | options) 38 | case "${line[1]}" in 39 | fadd) 40 | _arguments \ 41 | '(- : *)'{-h,--help}'[show help information]' \ 42 | '(-f --file -d --dir -h --help)'{-f,--file}'[select files from PWD and stage]' \ 43 | '(-d --dir -f --file -h --help)'{-d,--dir}'[select directory from PWD and stage]' \ 44 | && ret=0 45 | ;; 46 | fbackup) 47 | _arguments \ 48 | '(- : *)'{-h,--help}'[show help information]' \ 49 | '(-s --select -p --path -h --help)'{-s,--select}'[select tracked files to backup]' \ 50 | '(-p --path -s --select -h --help)'{-p,--path}'[sepcify path of files to backup]:filename:_files' \ 51 | '(-m --move -h --help)'{-m,--move}'[use mv cmd instead of cp cmd]' \ 52 | && ret=0 53 | ;; 54 | fcheckout) 55 | _arguments \ 56 | '(- : *)'{-h,--help}'[show help information]' \ 57 | '(-s --select -b --branch -c --commit -h --help)'{-s,--select}'[select files and then checkout them in selected commits]' \ 58 | '(-b --branch -s --select -c --commit -h --help)'{-b,--branch}'[checkout branch]' \ 59 | '(-c --commit -b --branch -s --select -h --help)'{-c,--commit}'[checkout commit]' \ 60 | '(-y --yes -h --help)'{-y,--yes}'[acknowledge all actions and skip confirmation]' \ 61 | && ret=0 62 | ;; 63 | fedit) 64 | _arguments \ 65 | '(- : *)'{-h,--help}'[show help information]' \ 66 | '(-m --modified -c --commit -h --help)'{-m,--modified}'[edit modified files]' \ 67 | '(-c --commit -m --modified -h --help)'{-c,--commit}'[edit commits]' \ 68 | && ret=0 69 | ;; 70 | fgrep) 71 | _arguments \ 72 | '(- : *)'{-h,--help}'[show help information]' \ 73 | '(-f --full -c --col)'{-f,--full}'[include all columns during fzf search, as if using "--col 1"]' \ 74 | '(-f --full -c --col)'{-c,--col}'[specify a column number to start searching in fzf]: :->cols' \ 75 | && ret=0 76 | ;; 77 | finit) 78 | _arguments \ 79 | '(- : *)'{-h,--help}'[show help information]' \ 80 | '(-u --url -h --help)'{-u,--url}'[migrate remote dotfiles to current system]: :->url' \ 81 | '(-s --submodule -h --help)'{-s,--submodule}'[clone submodules during migration]' \ 82 | '(-y --yes -h --help)'{-y,--yes}'[acknowledge all actions and skip confirmation]' \ 83 | && ret=0 84 | ;; 85 | flog) 86 | _arguments \ 87 | '(- : *)'{-h,--help}'[show help information]' \ 88 | '(-r --revert -R --reset -e --edit -c --checkout -h --help)'{-r,--revert}'[revert the selected commit and skip action menu]' \ 89 | '(-r --revert -R --reset -e --edit -c --checkout -h --help)'{-R,--reset}'[reset the selected commit and skip action menu]' \ 90 | '(-r --revert -R --reset -e --edit -c --checkout -h --help)'{-e,--edit}'[edit the selected commit and skip action menu]' \ 91 | '(-r --revert -R --reset -e --edit -c --checkout -h --help)'{-c,--checkout}'[checkout the selected commit and skip action menu]' \ 92 | '(-y --yes -h --help)'{-y,--yes}'[acknowledge all actions and skip confirmation]' \ 93 | && ret=0 94 | ;; 95 | freset) 96 | _arguments \ 97 | '(- : *)'{-h,--help}'[show help information]' \ 98 | '(-c --commit -h --help)'{-c,--commit}'[reset HEAD to certain commit]' \ 99 | '(-S --soft -H --hard -h --help)'{-S,--soft}'[reset commit using --soft flag]' \ 100 | '(-H --hard -S --soft -h --help)'{-H,--hard}'[reset commit using --hard flag]' \ 101 | '(-y --yes -h --help)'{-y,--yes}'[acknowledge all actions and skip confirmation]' \ 102 | && ret=0 103 | ;; 104 | fstash) 105 | _arguments \ 106 | '(- : *)'{-h,--help}'[show help information]' \ 107 | '(-s --select -d --delete -p --pop -h --help)'{-s,--select}'[list modified files and stash the selected files]' \ 108 | '(-s --select -d --delete -p --pop -h --help)'{-d,--delete}'[list stash and delete the selected stash]' \ 109 | '(-s --select -d --delete -p --pop -h --help)'{-p,--pop}'[use "stash pop" instead of "stash apply"]' \ 110 | && ret=0 111 | ;; 112 | fstat) 113 | _arguments \ 114 | '(- : *)'{-h,--help}'[show help information]' \ 115 | && ret=0 116 | ;; 117 | funtrack) 118 | _arguments \ 119 | '(- : *)'{-h,--help}'[show help information]' \ 120 | '(-t --temp -r --resume -h --help)'{-t,--temp}'[temporarily ignore changes of the selected files]' \ 121 | '(-t --temp -r --resume -h --help)'{-r,--resume}'[resume tracking changes of the selected files]' \ 122 | '(-y --yes -h --help)'{-y,--yes}'[acknowledge all actions and skip confirmation]' \ 123 | && ret=0 124 | ;; 125 | fupgrade) 126 | _arguments \ 127 | '(- : *)'{-h,--help}'[show help information]' \ 128 | && ret=0 129 | ;; 130 | esac 131 | ;; 132 | esac 133 | 134 | return "${ret}"; 135 | } 136 | 137 | _dotbare "$@" 138 | -------------------------------------------------------------------------------- /pkg/dotbare.aur: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SCRIPT_DIR=/opt/dotbare 4 | ${SCRIPT_DIR}/dotbare "$@" 5 | -------------------------------------------------------------------------------- /pkg/dotbare.brew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SCRIPT_DIR=/usr/local/Cellar/dotbare/1.3.1 4 | ${SCRIPT_DIR}/dotbare "$@" 5 | -------------------------------------------------------------------------------- /scripts/fadd: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Stage the selected file to git bare repo 4 | # 5 | # @params 6 | # Globals 7 | # ${mydir}: string, current directory of the executing script 8 | # ${stage_type}: modified, new file, or directory to stage 9 | # ${selected_files}: bash array of user selected files to stage 10 | # Arguments 11 | # -h|--help: show help message 12 | # -f|--file: select a file in PWD to stage 13 | # -d|--dir: select a directory in PWD to stage 14 | 15 | set -e 16 | set -f 17 | 18 | mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 19 | source "${mydir}"/../helper/search_file.sh 20 | source "${mydir}"/../helper/set_variable.sh 21 | source "${mydir}"/../helper/git_query.sh 22 | 23 | function usage() { 24 | echo -e "Usage: dotbare fadd [-h] [-f] [-d] ... 25 | 26 | Select files/directories or modified files through fzf. 27 | Stage the selected file to the dotfile gitbare repo. 28 | 29 | Default: list all modified files and stage the selected files. 30 | 31 | Optional arguments: 32 | -h, --help\t\tshow this help message and exit. 33 | -f, --file\t\tselect files in current directory and stage the selected files. 34 | -d, --dir\t\tselect folders in current directory and stage the selected folders." 35 | } 36 | 37 | ####################################### 38 | # stage file 39 | # Arguments: 40 | # $1: array of files to stage 41 | ####################################### 42 | function stage_file() { 43 | local files=("$@") 44 | [[ "${#files[@]}" -eq 0 ]] && exit 1 45 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" add "${files[@]}" 46 | } 47 | 48 | stage_type="modified" 49 | selected_files=() 50 | 51 | while [[ "$#" -gt 0 ]]; do 52 | case "$1" in 53 | -f|--file) 54 | stage_type="file" 55 | shift 56 | ;; 57 | -d|--dir) 58 | stage_type="dir" 59 | shift 60 | ;; 61 | -h|--help) 62 | usage 63 | exit 0 64 | ;; 65 | *) 66 | echo "Invalid option: $1" >&2 67 | usage 68 | exit 1 69 | ;; 70 | esac 71 | done 72 | 73 | while IFS= read -r line; do 74 | selected_files+=("${line}") 75 | done < <( 76 | if [[ "${stage_type}" == "file" ]]; then 77 | search_file 'f' 78 | elif [[ "${stage_type}" == "dir" ]]; then 79 | search_file 'd' 80 | else 81 | get_modified_file "select files to stage" "unstaged" 82 | fi 83 | ) 84 | 85 | stage_file "${selected_files[@]}" 86 | -------------------------------------------------------------------------------- /scripts/fbackup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # backup all tracked files 4 | # 5 | # @params 6 | # Globals 7 | # ${mydir}: current dir of the script 8 | # ${backup_type}: types of backup, individual or all 9 | # ${selected_files}: selected files to backup 10 | # ${action_command}: actions to run, cp|mv 11 | # Arguments 12 | # -h|--help: show help message and exit 13 | # -s|--select: select individual files through fzf and backup 14 | # -p PATH|--path PATH: pass in path and backup 15 | # -m|--move: use mv to backup instead of cp 16 | 17 | set -e 18 | set -f 19 | 20 | mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 21 | source "${mydir}"/../helper/set_variable.sh 22 | source "${mydir}"/../helper/git_query.sh 23 | 24 | function usage() { 25 | echo -e "Usage: dotbare fbackup [-h] [-m] [-s] [-p PATH] ... 26 | 27 | Backup files to ${DOTBARE_BACKUP}. 28 | This is useful when untracking files or migrating to new machines. 29 | 30 | Default: backup all tracked files using cp command to ${DOTBARE_BACKUP} directory. 31 | 32 | optional arguments: 33 | -h, --help\t\tshow this help message and exit. 34 | -s, --select\t\tlist all tracked files and only backup the selected files. 35 | -p PATH, --path PATH\tspecify path of files to backup. 36 | -m, --move\t\tuse 'mv' instead of the default 'cp' command to backup." 37 | } 38 | 39 | ####################################### 40 | # backup passed in files while preserving directory info 41 | # Arguments: 42 | # $1: files to backup, separate by \n 43 | # $2: action command (cp|mv) 44 | ####################################### 45 | function dotbare_backup() { 46 | local selected_files="$1" 47 | local action_command="${2:-cp}" 48 | while IFS= read -r line; do 49 | dir_name=$(dirname "${line}") 50 | [[ ! -d "${DOTBARE_BACKUP}/${dir_name}" ]] && mkdir -p "${DOTBARE_BACKUP}/${dir_name}" 51 | [[ "${action_command}" == "cp" ]] \ 52 | && cp -av "${line}" "${DOTBARE_BACKUP}/${line}" \ 53 | && continue 54 | # Purposly didn't use the -v flag because in finit, error message were 55 | # directed to /dev/null but the cp/mv info will still be printed, causing confusion. 56 | [[ "${action_command}" == "mv" ]] \ 57 | && mv "${line}" "${DOTBARE_BACKUP}/${line}" \ 58 | && echo "${line} -> ${DOTBARE_BACKUP}/${line}" 59 | done <<< "${selected_files}" 60 | exit 0 61 | } 62 | 63 | backup_type="all" 64 | action_command='cp' 65 | selected_files="" 66 | 67 | while [[ "$#" -gt 0 ]]; do 68 | case "$1" in 69 | -s|--select) 70 | backup_type="select" 71 | shift 72 | ;; 73 | -p|--path) 74 | [[ -z "$2" ]] && echo "Invalid option: $1" >&2 && usage && exit 1 75 | selected_files="$2" 76 | shift 77 | shift 78 | ;; 79 | -m|--move) 80 | action_command="mv" 81 | shift 82 | ;; 83 | -h|--help) 84 | usage 85 | exit 0 86 | ;; 87 | *) 88 | echo "Invalid option: $1" >&2 89 | usage 90 | exit 1 91 | ;; 92 | esac 93 | done 94 | 95 | 96 | [[ -n "${selected_files}" ]] && dotbare_backup "${selected_files}" "${action_command}" 97 | 98 | cd "${DOTBARE_TREE}" 99 | if [[ "${backup_type}" == 'select' ]]; then 100 | selected_files=$(get_git_file "select files to backup" "raw") 101 | else 102 | selected_files=$(git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" \ 103 | ls-files --full-name --directory "${DOTBARE_TREE}") 104 | fi 105 | 106 | [[ -z "${selected_files}" ]] && exit 1 107 | dotbare_backup "${selected_files}" "${action_command}" 108 | -------------------------------------------------------------------------------- /scripts/fcheckout: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # checkout files/commit/branches using fzf 4 | # 5 | # @params 6 | # Globals 7 | # ${mydir}: current directory of the script, used for imports 8 | # ${action_type}: what type of git commands to use (branch|select|commit|modified) 9 | # ${selected_branch}: selected_branch to switch 10 | # ${selected_files}: selected_files to checkout 11 | # ${selected_commit}: selected commit to checkout 12 | # ${confirm}: confirm status of the user 13 | # Arguments 14 | # -h|--help: show help message 15 | # -s|--select: search all files instead of just the modified files 16 | # -b|--branch: search branch and checkout branch 17 | # -c|--commit: search commit and checkout commit 18 | 19 | set -e 20 | set -f 21 | 22 | mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 23 | source "${mydir}"/../helper/set_variable.sh 24 | source "${mydir}"/../helper/get_confirmation.sh 25 | source "${mydir}"/../helper/git_query.sh 26 | 27 | function usage() { 28 | echo -e "Usage: dotbare fcheckout [-h] [-s] [-b] [-c] [-y] ... 29 | 30 | Select files/commit/branch through fzf and checkout the selected objects. 31 | Files: checkout the version in HEAD or in a specific commit (reset files content back to the selected commit). 32 | Branch: switch to the selected branch. 33 | Commit: switch to a specific commit. 34 | 35 | Default: list all modified files and reset selected files back to HEAD. 36 | 37 | Optional arguments: 38 | -h, --help\t\tshow this help message and exit. 39 | -s, --select\t\tlist all tracked files and select a commit to checkout the selected files. 40 | -b, --branch\t\tlist all branch and checkout/switch the selected branch. 41 | -c, --commit\t\tlist all commits and checkout selected commit. 42 | -y, --yes\t\tacknowledge all actions that will be taken and skip confirmation." 43 | } 44 | 45 | action_type="modified" 46 | selected_files=() 47 | confirm="" 48 | selected_commit="" 49 | selected_branch="" 50 | 51 | while [[ "$#" -gt 0 ]]; do 52 | case "$1" in 53 | -s|--select) 54 | action_type="select" 55 | shift 56 | ;; 57 | -b|--branch) 58 | action_type="branch" 59 | shift 60 | ;; 61 | -c|--commit) 62 | action_type="commit" 63 | shift 64 | ;; 65 | -y|--yes) 66 | confirm="y" 67 | shift 68 | ;; 69 | -h|--help) 70 | usage 71 | exit 0 72 | ;; 73 | *) 74 | echo "Invalid option: $1" >&2 75 | usage 76 | exit 1 77 | ;; 78 | esac 79 | done 80 | 81 | if [[ "${action_type}" == "branch" ]]; then 82 | # checkout branch 83 | selected_branch=$(get_branch 'select a branch to checkout') 84 | [[ -z "${selected_branch}" ]] && exit 1 85 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" checkout "${selected_branch}" 86 | elif [[ "${action_type}" == "commit" ]]; then 87 | # checkout commit 88 | selected_commit=$(get_commit 'select a commit to checkout') 89 | [[ -z "${selected_commit}" ]] && exit 1 90 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" checkout "${selected_commit}" 91 | elif [[ "${action_type}" == "modified" ]]; then 92 | # checkout modified file back to version in HEAD 93 | while IFS= read -r line; do 94 | selected_files+=("${line}") 95 | done < <(get_modified_file 'select files to checkout version in HEAD') 96 | [[ "${#selected_files[@]}" -eq 0 ]] && exit 1 97 | [[ -z "${confirm}" ]] && echo "(dryrun) dotbare checkout --" "${selected_files[@]}" 98 | [[ -z "${confirm}" ]] && confirm=$(get_confirmation "Confirm?") 99 | [[ "${confirm}" != 'y' ]] && exit 1 100 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" checkout -- "${selected_files[@]}" 101 | elif [[ "${action_type}" == "select" ]]; then 102 | # checkout selected files to a selected commit 103 | while IFS= read -r line; do 104 | selected_files+=("${line}") 105 | done < <(get_git_file 'select files to checkout to previous commit') 106 | [[ "${#selected_files[@]}" -eq 0 ]] && exit 1 107 | # continue select a commit and then checkout the file back to the selected commit 108 | selected_commit=$(get_commit 'select the target commit' "${selected_files[@]}") 109 | [[ -z "${selected_commit}" ]] && exit 1 110 | [[ -z "${confirm}" ]] && echo "(dryrun) dotbare checkout ${selected_commit} --" "${selected_files[@]}" 111 | [[ -z "${confirm}" ]] && confirm=$(get_confirmation "Confirm?") 112 | [[ "${confirm}" != 'y' ]] && exit 0 113 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" checkout "${selected_commit}" "${selected_files[@]}" 114 | fi 115 | -------------------------------------------------------------------------------- /scripts/fedit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # interactive menu to select file/commit to edit 4 | # 5 | # @params 6 | # Globals 7 | # ${mydir}: current directory of the script 8 | # ${edit_type}: which type to edit, all files, modified files, commit 9 | # ${selected_commit}: selected commit to edit 10 | # ${selected_files}: arrays of selected file to edit 11 | # Arguments 12 | # -m|--modified: display modified file only 13 | # -c|--commit: edit commit using interactive rebase 14 | # -h|--help: show helpe message and exit 15 | 16 | set -e 17 | set -f 18 | 19 | mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 20 | source "${mydir}"/../helper/set_variable.sh 21 | source "${mydir}"/../helper/git_query.sh 22 | 23 | function usage() { 24 | echo -e "Usage: dotbare fedit [-h] [-m] [-c] ... 25 | 26 | Select files/commits through fzf and edit selected files/commits in EDITOR. 27 | 28 | Default: list all tracked dotfiles and edit the selected files. 29 | 30 | Optional arguments: 31 | -h, --help\t\tshow this help message and exit. 32 | -m, --modified\tonly list and edit selected modified files. 33 | -c, --commit\t\tlist commit and edit the selected commit through interactive rebase." 34 | } 35 | 36 | edit_type="all" 37 | selected_files=() 38 | selected_commit="" 39 | 40 | while [[ "$#" -gt 0 ]]; do 41 | case "$1" in 42 | -m|--modified) 43 | edit_type="modified" 44 | shift 45 | ;; 46 | -c|--commit) 47 | edit_type="commit" 48 | shift 49 | ;; 50 | -h|--help) 51 | usage 52 | exit 0 53 | ;; 54 | *) 55 | echo "Invalid option: $1" >&2 56 | usage 57 | exit 1 58 | ;; 59 | esac 60 | done 61 | 62 | if [[ "${edit_type}" == "commit" ]]; then 63 | selected_commit=$(get_commit "select a commit to edit") 64 | [[ -z "${selected_commit}" ]] && exit 1 65 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" rebase -i "${selected_commit}"~ 66 | else 67 | while IFS= read -r line; do 68 | selected_files+=("${line}") 69 | done < <( 70 | if [[ "${edit_type}" == "modified" ]]; then 71 | get_modified_file "select files to edit" 72 | else 73 | get_git_file "select files to edit" 74 | fi 75 | ) 76 | [[ "${#selected_files[@]}" -eq 0 ]] && exit 1 77 | exec "${EDITOR}" "${selected_files[@]}" 78 | fi 79 | -------------------------------------------------------------------------------- /scripts/fgrep: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Grep for words within all dotfiles 4 | # 5 | # @params 6 | # Globals 7 | # mydir: path to this current script 8 | # selected_lines: selected lines to edit 9 | # fzf_search_delimiter: the col to start searching in fzf 10 | # Arguments 11 | # -h|--help: show help message and exit 12 | # -c COL| --col COL: use a different delimiter in fzf search 13 | # -f|--full: include file name in fzf searching, as if using --col 1 14 | 15 | set -e 16 | set -f 17 | 18 | mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 19 | source "${mydir}"/../helper/set_variable.sh 20 | source "${mydir}"/../helper/git_query.sh 21 | 22 | function usage() { 23 | echo -e "Usage: dotbare fgrep [-h] [-c] [-f] ... 24 | 25 | Grep words within tracked files and select to edit matches. 26 | 27 | Default: start searching from 3rd column (excluding the file name during search). 28 | 29 | Optional arguments: 30 | -h, --help\t\tshow this help message and exit. 31 | -c COL, --col COL\tspecify the column number to start searching. 32 | -f, --full\t\tinclude all column during search, as if using '--col 1'." 33 | } 34 | 35 | selected_lines=() 36 | fzf_search_delimiter=3 37 | 38 | while [[ "$#" -gt 0 ]]; do 39 | case "$1" in 40 | -c|--col) 41 | fzf_search_delimiter="$2" 42 | shift 43 | shift 44 | ;; 45 | -f|--full) 46 | fzf_search_delimiter=1 47 | shift 48 | ;; 49 | -h|--help) 50 | usage 51 | exit 0 52 | ;; 53 | *) 54 | echo "Invalid option: $1" >&2 55 | usage 56 | exit 1 57 | ;; 58 | esac 59 | done 60 | 61 | while IFS= read -r line; do 62 | case "${EDITOR}" in 63 | vim|nvim|nano) 64 | # line number = "${line##*:}" 65 | # file name = "${line%%:*}" 66 | selected_lines+=(+"${line##*:}" "${line%%:*}") 67 | ;; 68 | *) 69 | selected_lines+=("${line}") 70 | ;; 71 | esac 72 | done < <(grep_words "select matches to edit" "${fzf_search_delimiter}") 73 | 74 | [[ "${#selected_lines[@]}" -eq 0 ]] && exit 1 75 | 76 | "${EDITOR}" "${selected_lines[@]}" 77 | -------------------------------------------------------------------------------- /scripts/finit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # init or migrate the git bare repo 4 | # 5 | # @params 6 | # Globals 7 | # ${mydir}: current dir of the script 8 | # ${confirm}: confirm status of the user 9 | # ${post_hooks}: array of post checkout actions to perform 10 | # ${remote_url}; remote_url to clone and migrate 11 | # Arguments 12 | # -h|--help: show help message and exit 13 | # -u URL|--url URL: specify remote dotfiles url to init 14 | # -s|--select: clone submodules after checkout 15 | # -y|--yes: confirm action by default and skip confirmation 16 | 17 | set -e 18 | set -f 19 | 20 | mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 21 | source "${mydir}"/../helper/set_variable.sh 22 | source "${mydir}"/../helper/get_confirmation.sh 23 | 24 | function usage() { 25 | echo -e "Usage: dotbare finit [-h] [-y] [-s] [-u URL] ... 26 | 27 | Init the git bare repository if doesn't exist or migrate existing dotfiles to current system. 28 | The bare repository will be initialised under \$DOTBARE_DIR, default to \$HOME/.cfg if not set. 29 | It will track \$DOTBARE_TREE, default to \$HOME if not set. 30 | 31 | Migration example: 32 | dotbare finit -u URL --submodule 33 | 34 | Default: init the bare repository at $DOTBARE_DIR. 35 | 36 | Optional arguments: 37 | -h, --help\t\tshow this help message and exit. 38 | -u URL, --url URL\tmigrate existing dotfiles from remote git repo to current system. 39 | -s, --submodule\tclone submodules during migration. 40 | -y, --yes\t\tacknowledge all actions that will be taken and skip confirmation." 41 | } 42 | 43 | remote_url="" 44 | post_hooks=() 45 | confirm="" 46 | 47 | while [[ "$#" -gt 0 ]]; do 48 | case "$1" in 49 | -s|--submodule) 50 | [[ ! "${post_hooks[*]}" =~ submodule ]] && \ 51 | post_hooks+=("submodule") 52 | shift 53 | ;; 54 | -u|--url) 55 | [[ -z "$2" ]] && echo "Invalid option: $1" >&2 && usage && exit 1 56 | remote_url="$2" 57 | shift 58 | shift 59 | ;; 60 | -y|--yes) 61 | confirm='y' 62 | shift 63 | ;; 64 | -h|--help) 65 | usage 66 | exit 0 67 | ;; 68 | *) 69 | echo "Invalid option: $1" >&2 70 | usage 71 | exit 1 72 | ;; 73 | esac 74 | done 75 | 76 | if [[ -z "${remote_url}" ]]; then 77 | echo "git bare repository will be initialised at ${DOTBARE_DIR}" 78 | echo "git bare repository will be tracking ${DOTBARE_TREE}" 79 | [[ -z "${confirm}" ]] && confirm=$(get_confirmation) 80 | [[ "${confirm}" != 'y' ]] && exit 1 81 | 82 | if [[ -d "${DOTBARE_DIR}" ]]; then 83 | echo "${DOTBARE_DIR} already exist" 84 | exit 1 85 | else 86 | git init --bare "${DOTBARE_DIR}" 87 | git --git-dir "${DOTBARE_DIR}" --work-tree "${DOTBARE_TREE}" \ 88 | config --local status.showUntrackedFiles no 89 | fi 90 | else 91 | [[ ! -d "${DOTBARE_TREE}" ]] && mkdir -p "${DOTBARE_TREE}" 92 | cd "${DOTBARE_TREE}" 93 | git clone --bare "${remote_url}" "${DOTBARE_DIR}" 94 | 95 | set +e 96 | while ! git --git-dir "${DOTBARE_DIR}" --work-tree "${DOTBARE_TREE}" checkout 2> /dev/null; do 97 | echo "Resolving conflicts ..." 98 | git --git-dir "${DOTBARE_DIR}" --work-tree "${DOTBARE_TREE}" checkout 2>&1 \ 99 | | awk '{ 100 | if ($0 ~ /[\t].*/) { 101 | gsub(/^[\t]/, "", $0) 102 | print $0 103 | } 104 | }' \ 105 | | xargs -I __ "${mydir}"/fbackup -p __ -m 2> /dev/null 106 | if git --git-dir "${DOTBARE_DIR}" --work-tree "${DOTBARE_TREE}" checkout 2> /dev/null; then 107 | echo "All conflicts resolved" 108 | break 109 | fi 110 | done 111 | set -e 112 | 113 | git --git-dir "${DOTBARE_DIR}" --work-tree "${DOTBARE_TREE}" \ 114 | config --local status.showUntrackedFiles no 115 | echo "File checkout succeeded" 116 | 117 | for hook in "${post_hooks[@]}"; do 118 | case "${hook}" in 119 | submodule) 120 | echo "Cloning submodules ..." 121 | git --git-dir "${DOTBARE_DIR}" --work-tree "${DOTBARE_TREE}" \ 122 | submodule update --init --recursive 123 | ;; 124 | esac 125 | done 126 | 127 | echo "Migration completed" 128 | exit 0 129 | fi 130 | -------------------------------------------------------------------------------- /scripts/flog: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # git log interactive viewer 4 | # 5 | # @params 6 | # Globals 7 | # ${mydir}: current dir of the script 8 | # ${selected_action}: action to take on the selected commit 9 | # ${selected_commit}: user selected commit 10 | # ${confirm}: confirm status of user 11 | # Arguments 12 | # -h|--help: display help message 13 | # -r|--revert: revert the selected commit 14 | # -R|--reset: reset HEAD back to the selected commit 15 | # -e|--edit: edit commmit (interactive rebase) 16 | # -c|--checkout: checkout selected commmit 17 | # -y|--yes: confirm action by default and skip confirmation 18 | 19 | set -e 20 | set -f 21 | 22 | mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 23 | source "${mydir}"/../helper/set_variable.sh 24 | source "${mydir}"/../helper/git_query.sh 25 | source "${mydir}"/../helper/get_confirmation.sh 26 | 27 | function usage() { 28 | echo -e "Usage: dotbare flog [-h] [-r] [-R] [-e] [-c] [-y] ... 29 | 30 | Interactive log viewer with action menu. 31 | Action menu contains options including revert|reset|edit|checkout|exit. 32 | 33 | Default: list all commits and prompt a menu to select action to perform. 34 | 35 | Optional arguments: 36 | -h, --help\t\tshow this help message and exit. 37 | -r, --revert\t\trevert the selected commit and skip action menu. 38 | -R, --reset\t\treset HEAD back to selected commit and skip action menu. 39 | -e, --edit\t\tedit selected commit through interactive rebase and skip action menu. 40 | -c, --checkout\tcheckout selected commit and skip action menu. 41 | -y, --yes\t\tacknowledge all actions that will be taken and skip confirmation." 42 | } 43 | 44 | ####################################### 45 | # draw action menu for selected commit 46 | # Arguments: 47 | # $1: selected commit hash, used to display commit message in fzf header 48 | # $2: selected action, if selected, skip menu, return action 49 | # Outputs: 50 | # ${selected_action}: user selected action 51 | ####################################### 52 | function draw_menu() { 53 | local selected_commit="$1" 54 | local selected_action="$2" 55 | local menu header message 56 | if [[ -n "$selected_action" ]]; then 57 | echo "${selected_action}" 58 | else 59 | menu="revert: revert the selected commit\n" 60 | menu="${menu}reset: reset HEAD to the selected commit using --mixed flag\n" 61 | menu="${menu}edit: edit selected commit through interactive rebase\n" 62 | menu="${menu}checkout: checkout the selected commit\n" 63 | menu="${menu}exit: quit dotbare flog" 64 | message=$( 65 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" \ 66 | log --format=%B -n 1 "${selected_commit}" 67 | ) 68 | header="commit ${selected_commit}: ${message}" 69 | selected_action=$(echo -e "${menu}" \ 70 | | fzf --no-multi --header="${header}" \ 71 | | awk -F ":" '{ 72 | print $1 73 | }' 74 | ) 75 | echo "${selected_action}" 76 | fi 77 | } 78 | 79 | selected_action="" 80 | selected_commit="" 81 | confirm="" 82 | 83 | while [[ "$#" -gt 0 ]]; do 84 | case "$1" in 85 | -r|--revert) 86 | selected_action="revert" 87 | shift 88 | ;; 89 | -R|--reset) 90 | selected_action="reset" 91 | shift 92 | ;; 93 | -e|--edit) 94 | selected_action="edit" 95 | shift 96 | ;; 97 | -c|--checkout) 98 | selected_action="checkout" 99 | shift 100 | ;; 101 | -y|--yes) 102 | confirm='y' 103 | shift 104 | ;; 105 | -h|--help) 106 | usage 107 | exit 0 108 | ;; 109 | *) 110 | echo "Invalid option: $1" >&2 111 | usage 112 | exit 1 113 | ;; 114 | esac 115 | done 116 | 117 | while :; do 118 | selected_commit=$(get_commit) 119 | [[ -z "${selected_commit}" ]] && exit 1 120 | selected_action=$(draw_menu "${selected_commit}" "${selected_action}") 121 | [[ -n "${selected_action}" ]] && break 122 | done 123 | 124 | if [[ "${selected_action}" != 'exit' ]]; then 125 | if [[ "${selected_action}" == "reset" ]] && [[ -z "${confirm}" ]]; then 126 | echo "(dryrun) reset HEAD to ${selected_commit}" 127 | elif [[ -z "${confirm}" ]]; then 128 | echo "(dryrun) ${selected_action} ${selected_commit}" 129 | fi 130 | [[ -z "${confirm}" ]] && confirm=$(get_confirmation) 131 | [[ "${confirm}" != 'y' ]] && exit 1 132 | fi 133 | 134 | case "${selected_action}" in 135 | revert) 136 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" \ 137 | revert "${selected_commit}" 138 | ;; 139 | reset) 140 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" \ 141 | reset "${selected_commit}" 142 | ;; 143 | edit) 144 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" \ 145 | rebase -i "${selected_commit}"~ 146 | ;; 147 | checkout) 148 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" \ 149 | checkout "${selected_commit}" 150 | ;; 151 | exit) 152 | exit 0 153 | ;; 154 | *) 155 | exit 1 156 | ;; 157 | esac 158 | -------------------------------------------------------------------------------- /scripts/freset: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # unstage the selected staged file 4 | # or reset the commit to certain point 5 | # 6 | # @params 7 | # Globals 8 | # ${mydir}: current directory of the script 9 | # ${reset_type}: reset type, modified files or commit 10 | # ${reset_option}: git reset flag, --mixed | --soft | --hard 11 | # ${selected_files}: selected file to reset 12 | # ${selected_commit}: selected commit to reset 13 | # ${confirm}: confirmation status of the user 14 | # Arguments 15 | # -h|--help: show help message and quit 16 | # -c|--commit: reset commit 17 | # -S|--soft: use --soft flag 18 | # -H|--hard: use --hard flag 19 | # -y|--yes: confirm action by default and skip confirmation 20 | 21 | set -e 22 | set -f 23 | 24 | mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 25 | source "${mydir}"/../helper/set_variable.sh 26 | source "${mydir}"/../helper/get_confirmation.sh 27 | source "${mydir}"/../helper/git_query.sh 28 | 29 | function usage() { 30 | echo -e "Usage: dotbare freset [-h] [-c] [-S] [-H] [-y] ... 31 | 32 | Reset(unstage) the selected staged files. 33 | Reset the HEAD to certain commits by using -c flag. 34 | 35 | Default: unstage the selected files. 36 | 37 | Optional arguments: 38 | -h, --help\t\tshow this help message and exit. 39 | -c, --commit\t\treset HEAD to certain commit, default --mixed flag, reset HEAD to certain commit put all changes into modified state. 40 | -S, --soft\t\treset commit using --soft flag, reset HEAD to certain commit without modify working tree. 41 | -H, --hard\t\treset commit using --hard flag, reset HEAD to certain commit discard all changes from the working tree. 42 | -y, --yes\t\tacknowledge all actions that will be taken and skip confirmation." 43 | } 44 | 45 | reset_option="--mixed" 46 | reset_type="modified" 47 | selected_files=() 48 | confirm="" 49 | selected_commit="" 50 | 51 | while [[ "$#" -gt 0 ]]; do 52 | case "$1" in 53 | -c|--commit) 54 | reset_type="commit" 55 | shift 56 | ;; 57 | -S|--soft) 58 | reset_option="--soft" 59 | shift 60 | ;; 61 | -H|--hard) 62 | reset_option="--hard" 63 | shift 64 | ;; 65 | -y|--yes) 66 | confirm='y' 67 | shift 68 | ;; 69 | -h|--help) 70 | usage 71 | exit 0 72 | ;; 73 | *) 74 | echo "Invalid option: $1" >&2 75 | usage 76 | exit 1 77 | ;; 78 | esac 79 | done 80 | 81 | if [[ "${reset_type}" == "commit" ]]; then 82 | selected_commit=$(get_commit "select the target commit") 83 | [[ -z "${selected_commit}" ]] && exit 1 84 | [[ -z "${confirm}" ]] && confirm=$(get_confirmation "Reset HEAD to ${selected_commit} ${reset_option}?") 85 | [[ "${confirm}" != 'y' ]] && exit 1 86 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" reset "${selected_commit}" "${reset_option}" 87 | else 88 | while IFS= read -r line; do 89 | selected_files+=("${line}") 90 | done < <(get_modified_file 'select files to unstage' 'staged') 91 | [[ "${#selected_files[@]}" -eq 0 ]] && exit 1 92 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" reset "${selected_files[@]}" 93 | fi 94 | -------------------------------------------------------------------------------- /scripts/fstash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # stash operation using fzf 4 | # 5 | # @params 6 | # Globals 7 | # ${mydir}: current dir of the script, source purpose 8 | # ${stash_command}: stash command, pop, apply or file/delete to stash file or delete stash 9 | # ${selected_files}: selected files to stash 10 | # ${selected_stash}: selected stash to apply 11 | # ${confirm}: user confirm status 12 | # Arguments 13 | # -h|--help: show help message 14 | # -s|--select: select individual files and stash 15 | # -d|--delete: delete selected stash 16 | # -p|--pop: use pop instead of apply on the selected stash 17 | 18 | set -e 19 | set -f 20 | 21 | mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 22 | source "${mydir}"/../helper/set_variable.sh 23 | source "${mydir}"/../helper/get_confirmation.sh 24 | source "${mydir}"/../helper/git_query.sh 25 | 26 | function usage() { 27 | echo -e "Usage: dotbare fstash [-h] [-s] [-d] [-p] ... 28 | 29 | View and manage stash interactively. 30 | 31 | Default: list all stashes and apply the selected stash. 32 | 33 | Optional arguments: 34 | -h, --help\t\tshow this help message and exit. 35 | -s, --select\t\tlist modified files and stash the selected files. 36 | -d, --delete\t\tlist all stashes and delete the selected stash from stash list. 37 | -p, --pop\t\tuse 'stash pop' instead of 'stash apply'." 38 | } 39 | 40 | stash_command="apply" 41 | selected_files=() 42 | selected_stash="" 43 | confirm="" 44 | 45 | while [[ "$#" -gt 0 ]]; do 46 | case "$1" in 47 | -p|--pop) 48 | stash_command="pop" 49 | shift 50 | ;; 51 | -s|--select) 52 | stash_command="select" 53 | shift 54 | ;; 55 | -d|--delete) 56 | stash_command="delete" 57 | shift 58 | ;; 59 | -y|--yes) 60 | confirm="y" 61 | shift 62 | ;; 63 | -h|--help) 64 | usage 65 | exit 0 66 | ;; 67 | *) 68 | echo "Invalid option: $1" >&2 69 | usage 70 | exit 1 71 | ;; 72 | esac 73 | done 74 | 75 | if [[ "${stash_command}" == "select" ]]; then 76 | while IFS= read -r line; do 77 | selected_files+=("${line}") 78 | done < <(get_modified_file "select files to add to a stash") 79 | [[ "${#selected_files[@]}" -eq 0 ]] && exit 1 80 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" stash -- "${selected_files[@]}" 81 | elif [[ "${stash_command}" == "delete" ]]; then 82 | selected_stash=$(get_stash "select stash to delete") 83 | [[ -z "${selected_stash}" ]] && exit 1 84 | [[ -z "${confirm}" ]] && \ 85 | while IFS= read -r line; do 86 | echo "(dryrun) drop ${line}" 87 | done <<< "${selected_stash}" 88 | [[ -z "${confirm}" ]] && confirm=$(get_confirmation) 89 | [[ "${confirm}" != 'y' ]] && exit 1 90 | while IFS= read -r line; do 91 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" stash drop "${line}" 92 | done <<< "${selected_stash}" 93 | else 94 | selected_stash=$(get_stash "select stash to apply" "true") 95 | [[ -z "${selected_stash}" ]] && exit 1 96 | [[ -z "${confirm}" ]] && echo "(dryrun) ${stash_command} ${selected_stash}" 97 | [[ -z "${confirm}" ]] && confirm=$(get_confirmation) 98 | [[ "${confirm}" != 'y' ]] && exit 1 99 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" stash "${stash_command}" "${selected_stash}" 100 | fi 101 | -------------------------------------------------------------------------------- /scripts/fstat: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # interactive git status menu 4 | # toggle stage and unstage 5 | # 6 | # @params 7 | # Globals 8 | # ${mydir}: current directory of where the script is running 9 | # ${selected_files}: raw selected file (with current git status prepend) 10 | # ${selected_filenames}: bash array of names for the selected_files 11 | # ${stage_file}: determine if current operation should be staging file or unstage 12 | # Arguments 13 | # -h|--help: show help message and exit 14 | 15 | set -e 16 | set -f 17 | 18 | mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 19 | source "${mydir}"/../helper/set_variable.sh 20 | source "${mydir}"/../helper/git_query.sh 21 | 22 | function usage() { 23 | echo -e "Usage: dotbare fstat [-h] ... 24 | 25 | Display interactive git status menu. 26 | Toggle file stage/unstage interactively. 27 | 28 | Optional arguments: 29 | -h, --help\t\tshow this help message and exit." 30 | } 31 | 32 | while [[ "$#" -gt 0 ]]; do 33 | case "$1" in 34 | -h|--help) 35 | usage 36 | exit 0 37 | ;; 38 | *) 39 | echo "Invalid option: $1" >&2 40 | usage 41 | exit 1 42 | ;; 43 | esac 44 | done 45 | 46 | while :; do 47 | # reset all variable and arrays for each loop 48 | selected_files=() 49 | selected_filenames=() 50 | stage_file="" 51 | 52 | while IFS= read -r line; do 53 | selected_files+=("${line}") 54 | done < <(get_modified_file "select files to stage/unstage" "all" "raw") 55 | [[ "${#selected_files[@]}" -eq 0 ]] && break 56 | 57 | # check if current operation should stage file or unstage file 58 | # if any file start with M but has char immediately follow it, new changes are made, stage file 59 | # if any file start with a space or tab, the file is not staged, stage file 60 | # otherwise, we unstage 61 | stage_file=$(printf '%s\n' "${selected_files[@]}" | awk '{ 62 | if ($0 ~ /^[A-Za-z][A-Za-z].*$/) { 63 | print "stage" 64 | } else if ($0 ~ /^[ \t].*$/) { 65 | print "stage" 66 | } 67 | }') 68 | 69 | while IFS= read -r line; do 70 | selected_filenames+=("${line}") 71 | done < <( 72 | printf '%s\n' "${selected_files[@]}" \ 73 | | awk -v home="${DOTBARE_TREE}" '{ 74 | $1="" 75 | gsub(/^[ \t]/, "", $0) 76 | gsub(/"/, "", $0) 77 | print home "/" $0 78 | }' 79 | ) 80 | 81 | if [[ -z "${stage_file}" ]]; then 82 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" reset --quiet HEAD "${selected_filenames[@]}" 83 | else 84 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" add "${selected_filenames[@]}" 85 | fi 86 | done 87 | -------------------------------------------------------------------------------- /scripts/funtrack: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # untrack selected files 4 | # 5 | # @params 6 | # Globals 7 | # ${mydir}: current dir of the script 8 | # ${track_type}: determine method to use for untrack, possible values: untrack, temp, resume 9 | # ${confirm}: user confirm status 10 | # ${selected_files}: arrays of user selected_files for operation 11 | # Arguments 12 | # -h|--help: display help message and exit 13 | # -t|--temp: temporarily untrack files 14 | # -r|--resume: resume track of temp untracked files 15 | # -y|--yes: confirm action by default and skip confirmation 16 | 17 | set -e 18 | set -f 19 | 20 | mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 21 | source "${mydir}"/../helper/set_variable.sh 22 | source "${mydir}"/../helper/git_query.sh 23 | source "${mydir}"/../helper/get_confirmation.sh 24 | 25 | function usage() { 26 | echo -e "Usage: dotbare funtrack [-h] [-t] [-r] [-y] ... 27 | 28 | Untrack selected files from git. 29 | 30 | Default: list all tracked files and permanently untrack the selected files (using git rm --cached filename). 31 | 32 | Files will be remove from index while keeping the file in your current system. 33 | However, when your other computers pull down the changes, the untracked files will be deleted. 34 | Make sure to run dotbare fbackup before pulling down the changes. 35 | 36 | Alternatively use the -t flag (using git update-index --assume-unchanged [path]) to temporarily 37 | untrack a file but keeping the files when other computers pull down the changes. 38 | More information please refer to dotbare's github. 39 | 40 | Optional arguments: 41 | -h, --help\t\tshow this help message and exit. 42 | -t, --temp\t\tlist all tracked files and temporarily ignore changes of the selected files. 43 | -r, --resume\t\tlist all tracked files and resume tracking changes of the selected files. 44 | -y, --yes\t\tacknowledge all actions that will be taken and skip confirmation." 45 | } 46 | 47 | track_type="untrack" 48 | selected_files=() 49 | confirm="" 50 | 51 | while [[ "$#" -gt 0 ]]; do 52 | case "$1" in 53 | -t|--temp) 54 | track_type="temp" 55 | shift 56 | ;; 57 | -r|--resume) 58 | track_type="retrack" 59 | shift 60 | ;; 61 | -y|--yes) 62 | confirm='y' 63 | shift 64 | ;; 65 | -h|--help) 66 | usage 67 | exit 0 68 | ;; 69 | *) 70 | echo "Invalid option: $1" >&2 71 | usage 72 | exit 1 73 | ;; 74 | esac 75 | done 76 | 77 | while IFS= read -r line; do 78 | selected_files+=("${line}") 79 | done < <(get_git_file "select files to untrack") 80 | [[ "${#selected_files[@]}" -eq 0 ]] && exit 1 81 | 82 | if [[ "${track_type}" == "temp" ]]; then 83 | [[ -z "${confirm}" ]] && echo "(dryrun) dotbare update-index --assume-unchanged" "${selected_files[@]}" 84 | [[ -z "${confirm}" ]] && confirm=$(get_confirmation "Files will be temporarily stop being tracked for changes, continue?") 85 | [[ "${confirm}" != 'y' ]] && exit 1 86 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" update-index --assume-unchanged "${selected_files[@]}" 87 | echo -e " " 88 | echo "Selected files are temporarily untracked by git, use dotbare funtrack -r to continue tracking changes." 89 | echo "Although dotbare funtrack -t won't delete the files on other machines, it is not the recommended way to untrack files." 90 | echo "dotbare funtrack -t is using git update-index --assume-unchanged under the hood" 91 | echo "Please refer to git update-index official documentation for more details or visit dotbare's github page" 92 | elif [[ "${track_type}" == "retrack" ]]; then 93 | [[ -z "${confirm}" ]] && echo "(dryrun) dotbare update-index --no-assume-unchanged" "${selected_files[@]}" 94 | [[ -z "${confirm}" ]] && confirm=$(get_confirmation "Files will resume being tracked by git, continue?") 95 | [[ "${confirm}" != 'y' ]] && exit 1 96 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" update-index --no-assume-unchanged "${selected_files[@]}" 97 | echo " " 98 | echo "Selected files are being resumed for tracking by git." 99 | echo "Although dotbare funtrack -t won't delete the files on other machines, it is not the recommended way to untrack files." 100 | echo "dotbare funtrack -t is using git update-index --assume-unchanged under the hood" 101 | echo "Please refer to git update-index official documentation for more details or visit dotbare's github page" 102 | else 103 | [[ -z "${confirm}" ]] && echo "(dryrun) dotbare rm --cached" "${selected_files[@]}" 104 | [[ -z "${confirm}" ]] && confirm=$(get_confirmation "Untrack the selected files?") 105 | [[ "${confirm}" != 'y' ]] && exit 1 106 | git --git-dir="${DOTBARE_DIR}" --work-tree="${DOTBARE_TREE}" rm --cached "${selected_files[@]}" 107 | echo -e " " 108 | echo "Selected files are being untracked by git, make sure to run dotbare fbackup on your other systems." 109 | echo "When other systems pull down this change, selected files will be deleted on other systems." 110 | echo "This is the default behavior of git rm --cached." 111 | echo "Please refer to git rm official documentation for more details or visit dotbare's github page" 112 | fi 113 | -------------------------------------------------------------------------------- /scripts/fupgrade: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # update dotbare to latest master 4 | 5 | set -f 6 | 7 | mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 8 | 9 | function usage() { 10 | echo -e "Usage: dotbare fupgrade [-h] ... 11 | 12 | Upgrade dotbare to the latest master. 13 | 14 | Optional arguments: 15 | -h, --help\t\tshow this help message and exit." 16 | } 17 | 18 | while [[ "$#" -gt 0 ]]; do 19 | case "$1" in 20 | -h|--help) 21 | usage 22 | exit 0 23 | ;; 24 | *) 25 | echo "Invalid option: $1" >&2 26 | usage 27 | exit 1 28 | ;; 29 | esac 30 | done 31 | 32 | # rip from omz 33 | # auto stash on rebase 34 | resetAutoStash=$(git config --bool rebase.autoStash 2>&1) 35 | git config rebase.autoStash true 36 | 37 | # change directory to dotbare folder 38 | cd "${mydir}/.." || exit 39 | 40 | echo "Updating dotbare ..." 41 | if git pull --rebase --stat origin master; then 42 | echo "dotbare updated successfully" 43 | else 44 | echo "Something went wrong, please try again or fire up an issue at https://github.com/kazhala/dotbare" 45 | fi 46 | 47 | # reset autostack to original value 48 | case "$resetAutoStash" in 49 | "") 50 | git config --unset rebase.autoStash 51 | ;; 52 | *) 53 | git config rebase.autoStash "${resetAutoStash}" 54 | ;; 55 | esac 56 | -------------------------------------------------------------------------------- /tests/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM bats/bats:latest 2 | RUN apk add --no-cache git 3 | RUN apk add --no-cache fzf 4 | ENV COLUMNS=80 5 | ADD ./ /root/dotbare 6 | RUN echo "source /root/dotbare/dotbare.plugin.bash" >> "$HOME"/.bashrc 7 | WORKDIR /root/dotbare 8 | ARG MIGRATE='url' 9 | RUN [ "$MIGRATE" = 'url' ] && ./dotbare finit -u https://github.com/kazhala/dotfiles.git || : 10 | RUN [ "$MIGRATE" = 'bare' ] && ./dotbare finit -y || : 11 | ENTRYPOINT ["bats", "tests"] 12 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # Testing dotbare 2 | 3 | `dotbare` is unit tested using the [bats](https://github.com/bats-core/bats-core) testing 4 | frame work. Interaction with `fzf` are mocked using the PATH override method. 5 | 6 | Refer to bats homepage for usage of bats and their test basics. 7 | 8 | ## Mocking 9 | 10 | One of the challenge when testing `dotbare` is interaction with `fzf`, `git` and some 11 | other shell functions. `fzf` is the most pain because it does require human interaction. 12 | 13 | Using the PATH override method, at the very least, we can assert if fzf is invoked with 14 | right arguments. 15 | 16 | ### How it works 17 | 18 | There is a executable file called fzf in the test folder as well as git, tree etc. Before 19 | running test that requires fzf invokations, append the test folder path to the front of 20 | PATH variable. 21 | 22 | ```sh 23 | #!/usr/bin/env bats 24 | 25 | stage_selected_dir() { 26 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 27 | bash "${BATS_TEST_DIRNAME}"/../dotbare fadd --dir 28 | } 29 | ``` 30 | 31 | This way the executable will be executed by `dotbare` instead of the real `fzf`. 32 | 33 | ### The fzf executable 34 | 35 | I'm sure there might be more elegant way of doing this, if you have suggestions please 36 | help me improve it. Currently for better readability in all the bats test file, I added 37 | bunch of `if` statement in the `fzf` executable to assert if `fzf` is being called 38 | correctly. 39 | 40 | ```sh 41 | if [[ "$*" =~ '--multi --preview ' ]] && [[ "$*" =~ "tree -L 1 -C --dirsfirst {}" ]]; then 42 | # dotbare fadd --dir -- "./fadd.bats" @test "fadd stage selected dir" 43 | echo "fadd_stage_dir" 44 | fi 45 | ``` 46 | 47 | When the executable is being called, it will check for it's arguments and echo out a shorter 48 | word indicating the correct argument is passed. 49 | 50 | ```sh 51 | #!/usr/bin/env bats 52 | 53 | @test "fadd stage selected dir" { 54 | run stage_selected_dir 55 | # we could assert if fzf is actually being invoked correctly 56 | # in this case, it's supposed to search directory and using tree to provide preview 57 | [[ "${output}" =~ "add fadd_stage_dir" ]] 58 | } 59 | ``` 60 | 61 | ## Full example 62 | 63 | > You could always checkout more examples in tests folder 64 | 65 | The fzf executable 66 | 67 | ```sh 68 | if [[ "$*" =~ '--header=select a commit' ]] && [[ "$*" =~ "show --color" ]]; then 69 | # dotbare flog --reset -y -- "./flog.bats" @test "flog reset" 70 | echo "--flog_reset" 71 | fi 72 | ``` 73 | 74 | The bats unit test file. 75 | 76 | ```sh 77 | #!/usr/bin/env bats 78 | 79 | help() { 80 | bash "${BATS_TEST_DIRNAME}"/../dotbare flog -h 81 | } 82 | reset() { 83 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 84 | bash "${BATS_TEST_DIRNAME}"/../dotbare flog --reset -y 85 | } 86 | 87 | @test "flog help" { 88 | run help 89 | [ "${status}" -eq 0 ] 90 | [ "${lines[0]}" = "Usage: dotbare flog [-h] [-r] [-R] [-e] [-c] [-y] ..." ] 91 | } 92 | @test "flog reset" { 93 | run reset 94 | [[ "${output}" =~ "reset --flog_reset" ]] 95 | } 96 | ``` 97 | -------------------------------------------------------------------------------- /tests/dotbare.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | help() { 4 | bash "${BATS_TEST_DIRNAME}"/../dotbare -h 5 | } 6 | 7 | addall() { 8 | bash "${BATS_TEST_DIRNAME}"/../dotbare add --all 9 | } 10 | 11 | routing() { 12 | "${BATS_TEST_DIRNAME}"/../dotbare fadd -h 13 | } 14 | 15 | routing2() { 16 | "${BATS_TEST_DIRNAME}"/../dotbare flog -h 17 | } 18 | 19 | normal_git() { 20 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 21 | "${BATS_TEST_DIRNAME}"/../dotbare add -h 22 | } 23 | 24 | invalid_command() { 25 | "${BATS_TEST_DIRNAME}"/../dotbare hello 26 | } 27 | 28 | version() { 29 | "${BATS_TEST_DIRNAME}"/../dotbare --version 30 | } 31 | 32 | no_argument() { 33 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 34 | "${BATS_TEST_DIRNAME}"/../dotbare 35 | } 36 | 37 | generic_git_operation_block_finit() { 38 | "${BATS_TEST_DIRNAME}"/../dotbare --git finit 39 | } 40 | 41 | generic_git_operation_block_fbackup() { 42 | "${BATS_TEST_DIRNAME}"/../dotbare --git fbackup 43 | } 44 | 45 | generic_git_operation_block_fupgrade() { 46 | "${BATS_TEST_DIRNAME}"/../dotbare --git fupgrade 47 | } 48 | 49 | generic_git_operation_init() { 50 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 51 | "${BATS_TEST_DIRNAME}"/../dotbare --git init 52 | } 53 | 54 | generic_git_operation_fadd() { 55 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 56 | "${BATS_TEST_DIRNAME}"/../dotbare --git fadd 57 | } 58 | 59 | @test "main generic git fadd" { 60 | run generic_git_operation_fadd 61 | [ "${status}" -eq 0 ] 62 | [[ "${output}" =~ "--git-dir=rev-parse --show-toplevel/.git --work-tree=rev-parse --show-toplevel" ]] 63 | [[ "${output}" =~ "fadd_stage_modified" ]] 64 | } 65 | 66 | @test "main generic git commands" { 67 | run generic_git_operation_init 68 | [ "${status}" -eq 0 ] 69 | [[ "${output}" =~ "--git-dir=rev-parse --show-toplevel/.git --work-tree=rev-parse --show-toplevel" ]] 70 | [[ "${output}" =~ "init" ]] 71 | } 72 | 73 | @test "main generic git flag block finit" { 74 | run generic_git_operation_block_finit 75 | [ "${status}" -eq 1 ] 76 | [ "${output}" = "dotbare finit is not supported when using dotbare as a generic fuzzy git tool" ] 77 | } 78 | 79 | @test "main generic git flag block fbackup" { 80 | run generic_git_operation_block_fbackup 81 | [ "${status}" -eq 1 ] 82 | [ "${output}" = "dotbare fbackup is not supported when using dotbare as a generic fuzzy git tool" ] 83 | } 84 | 85 | @test "main generic git flag block fupgrade" { 86 | run generic_git_operation_block_fupgrade 87 | [ "${status}" -eq 1 ] 88 | [ "${output}" = "dotbare fupgrade is not supported when using dotbare as a generic fuzzy git tool" ] 89 | } 90 | 91 | @test "main help" { 92 | run help 93 | [ "${status}" -eq 0 ] 94 | [ "${lines[0]}" = "Usage: dotbare [-h] [-v] [COMMANDS] [OPTIONS] ..." ] 95 | } 96 | 97 | @test "main version" { 98 | run version 99 | [ "${status}" -eq 0 ] 100 | [[ "${output}" =~ "Current dotbare version: ${DOTBARE_VERSION}" ]] 101 | } 102 | 103 | @test "main disable add --all" { 104 | run addall 105 | [ "${status}" -eq 1 ] 106 | [ "${lines[0]}" = "If you intend to stage all modified file, run dotbare add -u" ] 107 | } 108 | 109 | @test "main routing" { 110 | run routing 111 | [ "${status}" -eq 0 ] 112 | [ "${lines[0]}" = "Usage: dotbare fadd [-h] [-f] [-d] ..." ] 113 | } 114 | 115 | @test "main routing2" { 116 | run routing2 117 | [ "${status}" -eq 0 ] 118 | [ "${lines[0]}" = "Usage: dotbare flog [-h] [-r] [-R] [-e] [-c] [-y] ..." ] 119 | } 120 | 121 | @test "main git command" { 122 | run normal_git 123 | [ "${status}" -eq 0 ] 124 | [[ "${output}" =~ "add -h" ]] 125 | } 126 | 127 | @test "main invliad command" { 128 | run invalid_command 129 | [ "${status}" -eq 1 ] 130 | } 131 | 132 | @test "main no argument" { 133 | run no_argument 134 | [[ "${output}" =~ "Available commands" ]] 135 | } 136 | -------------------------------------------------------------------------------- /tests/fadd.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | help() { 4 | bash "${BATS_TEST_DIRNAME}"/../dotbare fadd -h 5 | } 6 | 7 | invalid_option() { 8 | bash "${BATS_TEST_DIRNAME}"/../dotbare fadd -p 9 | } 10 | 11 | no_file_selected() { 12 | cd "${BATS_TEST_DIRNAME}" 13 | bash "${BATS_TEST_DIRNAME}"/../dotbare fadd -d 14 | } 15 | 16 | stage_selected_file() { 17 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 18 | bash "${BATS_TEST_DIRNAME}"/../dotbare fadd -f 19 | } 20 | 21 | stage_selected_dir() { 22 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 23 | bash "${BATS_TEST_DIRNAME}"/../dotbare fadd --dir 24 | } 25 | 26 | stage_modified_file() { 27 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 28 | bash "${BATS_TEST_DIRNAME}"/../dotbare fadd 29 | } 30 | 31 | @test "fadd help" { 32 | run help 33 | [ "${status}" -eq 0 ] 34 | [ "${lines[0]}" = "Usage: dotbare fadd [-h] [-f] [-d] ..." ] 35 | } 36 | 37 | @test "fadd invalid option" { 38 | run invalid_option 39 | [ "${status}" -eq 1 ] 40 | [ "${lines[0]}" = "Invalid option: -p" ] 41 | } 42 | 43 | @test "fadd no file selected" { 44 | run no_file_selected 45 | [ "${status}" -eq 1 ] 46 | } 47 | 48 | @test "fadd stage selected file" { 49 | run stage_selected_file 50 | [[ "${output}" =~ "add fadd_stage_file" ]] 51 | } 52 | 53 | @test "fadd stage selected dir" { 54 | run stage_selected_dir 55 | [[ "${output}" =~ "add fadd_stage_dir" ]] 56 | } 57 | 58 | @test "fadd stage modified file" { 59 | run stage_modified_file 60 | [[ "${output}" =~ "add" ]] 61 | [[ "${output}" =~ "fadd_stage_modified" ]] 62 | } 63 | -------------------------------------------------------------------------------- /tests/fbackup.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | setup() { 4 | export DOTBARE_BACKUP="$HOME/.local/share/dotbare_test" 5 | export DOTBARE_DIR="${HOME}/.cfg/" 6 | } 7 | 8 | teardown() { 9 | [ -d "${DOTBARE_BACKUP}" ] && rm -r "${DOTBARE_BACKUP}" 10 | unset DOTBARE_BACKUP 11 | } 12 | 13 | help() { 14 | bash "${BATS_TEST_DIRNAME}"/../dotbare fbackup -h 15 | } 16 | 17 | invalid_option() { 18 | bash "${BATS_TEST_DIRNAME}"/../dotbare fbackup -f 19 | } 20 | 21 | backup() { 22 | bash "${BATS_TEST_DIRNAME}"/../dotbare fbackup 23 | } 24 | 25 | individual_backup() { 26 | cd "${BATS_TEST_DIRNAME}" 27 | bash "${BATS_TEST_DIRNAME}"/../dotbare fbackup -p fadd.bats 28 | } 29 | 30 | move_file() { 31 | touch bats_test.txt 32 | bash "${BATS_TEST_DIRNAME}"/../dotbare fbackup --path bats_test.txt -m 33 | } 34 | 35 | @test "fbackup help" { 36 | run help 37 | [ "${status}" -eq 0 ] 38 | [ "${lines[0]}" = "Usage: dotbare fbackup [-h] [-m] [-s] [-p PATH] ..." ] 39 | } 40 | 41 | @test "fbackup invalid option" { 42 | run invalid_option 43 | [ "${status}" -eq 1 ] 44 | [ "${lines[0]}" = 'Invalid option: -f' ] 45 | } 46 | 47 | @test "fbackup backup all files" { 48 | if ! "${BATS_TEST_DIRNAME}"/../dotbare log &>/dev/null; then 49 | run backup 50 | [ "${status}" -eq 1 ] 51 | else 52 | run backup 53 | [ "${status}" -eq 0 ] 54 | [ -f "${DOTBARE_BACKUP}"/.bashrc ] 55 | fi 56 | } 57 | 58 | @test "fbackup backup individual file" { 59 | run individual_backup 60 | [ "${status}" -eq 0 ] 61 | [ -f "${DOTBARE_BACKUP}"/fadd.bats ] 62 | } 63 | 64 | @test "fbackup move file" { 65 | run move_file 66 | [ "${status}" -eq 0 ] 67 | [ -f "${DOTBARE_BACKUP}"/bats_test.txt ] 68 | [ ! -f "${BATS_TEST_DIRNAME}"/bats_test.txt ] 69 | } 70 | -------------------------------------------------------------------------------- /tests/fcheckout.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | setup() { 4 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 5 | } 6 | 7 | help() { 8 | bash "${BATS_TEST_DIRNAME}"/../dotbare fcheckout -h 9 | } 10 | 11 | invalid_option() { 12 | bash "${BATS_TEST_DIRNAME}"/../dotbare fcheckout -p 13 | } 14 | 15 | checkout_branch() { 16 | bash "${BATS_TEST_DIRNAME}"/../dotbare fcheckout --branch 17 | } 18 | 19 | checkout_commit() { 20 | bash "${BATS_TEST_DIRNAME}"/../dotbare fcheckout -c 21 | } 22 | 23 | checkout_modified_file() { 24 | bash "${BATS_TEST_DIRNAME}"/../dotbare fcheckout -y 25 | } 26 | 27 | checkout_selected_file() { 28 | bash "${BATS_TEST_DIRNAME}"/../dotbare fcheckout --yes -s 29 | } 30 | 31 | @test "fcheckout help" { 32 | run help 33 | [ "${status}" -eq 0 ] 34 | [ "${lines[0]}" = "Usage: dotbare fcheckout [-h] [-s] [-b] [-c] [-y] ..." ] 35 | } 36 | 37 | @test "fcheckout invalid option" { 38 | run invalid_option 39 | [ "${status}" -eq 1 ] 40 | [ "${lines[0]}" = "Invalid option: -p" ] 41 | } 42 | 43 | @test "fcheckout branch" { 44 | run checkout_branch 45 | [[ "${output}" =~ "checkout fcheckout_branch" ]] 46 | } 47 | 48 | @test "fcheckout commit" { 49 | run checkout_commit 50 | [[ "${output}" =~ "checkout fcheckout_commit" ]] 51 | } 52 | 53 | @test "fcheckout modified" { 54 | run checkout_modified_file 55 | [[ "${output}" =~ "checkout" ]] 56 | [[ "${output}" =~ "fcheckout_modified" ]] 57 | } 58 | 59 | @test "fcheckout select" { 60 | run checkout_selected_file 61 | [[ "${output}" =~ "checkout" ]] 62 | [[ "${output}" =~ "fcheckout_select_gitfile" ]] 63 | [[ "${output}" =~ "fcheckout_select_commitdiff" ]] 64 | } 65 | -------------------------------------------------------------------------------- /tests/fedit.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | help() { 4 | bash "${BATS_TEST_DIRNAME}"/../dotbare fedit -h 5 | } 6 | 7 | invalid_option() { 8 | bash "${BATS_TEST_DIRNAME}"/../dotbare fedit -p 9 | } 10 | 11 | no_file_selected() { 12 | cd "${BATS_TEST_DIRNAME}" 13 | bash "${BATS_TEST_DIRNAME}"/../dotbare fedit -m 14 | } 15 | 16 | edit_commits() { 17 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 18 | bash "${BATS_TEST_DIRNAME}"/../dotbare fedit --commit 19 | } 20 | 21 | edit_files() { 22 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 23 | export EDITOR="echo" 24 | bash "${BATS_TEST_DIRNAME}"/../dotbare fedit 25 | } 26 | 27 | @test "fedit help" { 28 | run help 29 | [ "${status}" -eq 0 ] 30 | [ "${lines[0]}" = "Usage: dotbare fedit [-h] [-m] [-c] ..." ] 31 | } 32 | 33 | @test "fedit invalid option" { 34 | run invalid_option 35 | [ "${status}" -eq 1 ] 36 | [ "${lines[0]}" = "Invalid option: -p" ] 37 | } 38 | 39 | @test "fedit no file selected" { 40 | run no_file_selected 41 | [ "${status}" -eq 1 ] 42 | } 43 | 44 | @test "fedit edit commits" { 45 | run edit_commits 46 | [[ "${output}" =~ "rebase -i" ]] 47 | [[ "${output}" =~ "fedit_commits" ]] 48 | } 49 | 50 | @test "fedit edit files" { 51 | run edit_files 52 | [[ "${output}" =~ "fedit_files" ]] 53 | } 54 | -------------------------------------------------------------------------------- /tests/fgrep.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | help() { 4 | bash "${BATS_TEST_DIRNAME}"/../dotbare fgrep -h 5 | } 6 | 7 | invalid_option() { 8 | bash "${BATS_TEST_DIRNAME}"/../dotbare fgrep -p 9 | } 10 | 11 | edit_lines() { 12 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 13 | export EDITOR="echo" 14 | bash "${BATS_TEST_DIRNAME}"/../dotbare fgrep 15 | } 16 | 17 | full_deli() { 18 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 19 | export EDITOR="echo" 20 | bash "${BATS_TEST_DIRNAME}"/../dotbare fgrep --full 21 | } 22 | 23 | option_deli() { 24 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 25 | export EDITOR="echo" 26 | bash "${BATS_TEST_DIRNAME}"/../dotbare fgrep --col 2 27 | } 28 | 29 | @test "fgrep option delimiter" { 30 | run option_deli 31 | [[ "${output}" =~ "--nth 2.. --header=select matches to edit" ]] 32 | } 33 | 34 | @test "fgrep full delimiter" { 35 | run full_deli 36 | [[ "${output}" =~ "--nth 1.. --header=select matches to edit" ]] 37 | } 38 | 39 | @test "fgrep help" { 40 | run help 41 | [ "${status}" -eq 0 ] 42 | [ "${lines[0]}" = "Usage: dotbare fgrep [-h] [-c] [-f] ..." ] 43 | } 44 | 45 | @test "fgrep invalid option" { 46 | run invalid_option 47 | [ "${status}" -eq 1 ] 48 | [ "${lines[0]}" = "Invalid option: -p" ] 49 | } 50 | 51 | @test "fgrep edit lines" { 52 | run edit_lines 53 | [[ "${output}" =~ "--nth 3.. --header=select matches to edit" ]] 54 | } 55 | -------------------------------------------------------------------------------- /tests/finit.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | setup() { 4 | export DOTBARE_DIR="$HOME/.local/share/dotbare_test/.cfg" 5 | export DOTBARE_TREE="$HOME/.local/share/dotbare_test" 6 | } 7 | 8 | teardown() { 9 | if [[ "${DOTBARE_DIR}" == "$HOME/.local/share/dotbare_test/.cfg" ]] && \ 10 | [[ "${DOTBARE_TREE}" == "$HOME/.local/share/dotbare_test" ]]; then 11 | rm -rf "${DOTBARE_TREE}" 12 | fi 13 | unset DOTBARE_DIR 14 | unset DOTBARE_TREE 15 | } 16 | 17 | help() { 18 | bash "${BATS_TEST_DIRNAME}"/../dotbare finit -h 19 | } 20 | 21 | init() { 22 | bash "${BATS_TEST_DIRNAME}"/../dotbare finit --yes 23 | } 24 | 25 | migration() { 26 | bash "${BATS_TEST_DIRNAME}"/../dotbare finit -u https://github.com/kazhala/dotfiles.git 27 | } 28 | 29 | submodule() { 30 | bash "${BATS_TEST_DIRNAME}"/../dotbare finit -u https://github.com/kazhala/dotfiles.git -s --submodule 31 | } 32 | 33 | @test "finit help" { 34 | run help 35 | [ "${status}" -eq 0 ] 36 | [ "${lines[0]}" = "Usage: dotbare finit [-h] [-y] [-s] [-u URL] ..." ] 37 | } 38 | 39 | @test "finit init dotbare" { 40 | [[ -d "${DOTBARE_DIR}" ]] && rm -rf "${DOTBARE_DIR}" 41 | run init 42 | [ "${status}" -eq 0 ] 43 | run init 44 | [ "${status}" -eq 1 ] 45 | [[ "${output}" =~ "${DOTBARE_DIR} already exist" ]] 46 | } 47 | 48 | @test "finit migration" { 49 | [[ -d "${DOTBARE_DIR}" ]] && rm -rf "${DOTBARE_DIR}" 50 | run migration 51 | [ "${status}" -eq 0 ] 52 | [[ "${output}" =~ "Migration completed" ]] 53 | } 54 | 55 | @test "finit submodule" { 56 | [[ -d "${DOTBARE_DIR}" ]] && rm -rf "${DOTBARE_DIR}" 57 | run submodule 58 | [ "${status}" -eq 0 ] 59 | result=$(echo "${output}" | tr "\n" " ") 60 | [[ "${result}" =~ "Cloning submodules ... Migration completed" ]] 61 | } 62 | -------------------------------------------------------------------------------- /tests/flog.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | help() { 4 | bash "${BATS_TEST_DIRNAME}"/../dotbare flog -h 5 | } 6 | 7 | invalid_option() { 8 | bash "${BATS_TEST_DIRNAME}"/../dotbare flog -p 9 | } 10 | 11 | menu() { 12 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 13 | bash "${BATS_TEST_DIRNAME}"/../dotbare flog 14 | } 15 | 16 | reset() { 17 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 18 | bash "${BATS_TEST_DIRNAME}"/../dotbare flog --reset -y 19 | } 20 | 21 | @test "flog help" { 22 | run help 23 | [ "${status}" -eq 0 ] 24 | [ "${lines[0]}" = "Usage: dotbare flog [-h] [-r] [-R] [-e] [-c] [-y] ..." ] 25 | } 26 | 27 | @test "flog invalid option" { 28 | run invalid_option 29 | [ "${status}" -eq 1 ] 30 | [ "${lines[0]}" = "Invalid option: -p" ] 31 | } 32 | 33 | @test "flog menu" { 34 | run menu 35 | [ "${status}" -eq 0 ] 36 | } 37 | 38 | @test "flog reset" { 39 | run reset 40 | [[ "${output}" =~ "reset --flog_reset" ]] 41 | } 42 | -------------------------------------------------------------------------------- /tests/freset.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | help() { 4 | bash "${BATS_TEST_DIRNAME}"/../dotbare freset -h 5 | } 6 | 7 | invalid_option() { 8 | bash "${BATS_TEST_DIRNAME}"/../dotbare freset -p 9 | } 10 | 11 | no_selection_made() { 12 | bash "${BATS_TEST_DIRNAME}"/../dotbare freset 13 | } 14 | 15 | select_commit() { 16 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 17 | bash "${BATS_TEST_DIRNAME}"/../dotbare freset --commit -y 18 | } 19 | 20 | select_files() { 21 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 22 | bash "${BATS_TEST_DIRNAME}"/../dotbare freset 23 | } 24 | 25 | @test "freset help" { 26 | run help 27 | [ "${status}" -eq 0 ] 28 | [ "${lines[0]}" = "Usage: dotbare freset [-h] [-c] [-S] [-H] [-y] ..." ] 29 | } 30 | 31 | @test "freset invalid option" { 32 | run invalid_option 33 | [ "${status}" -eq 1 ] 34 | [ "${lines[0]}" = "Invalid option: -p" ] 35 | } 36 | 37 | @test "freset no selection made" { 38 | run no_selection_made 39 | [ "${status}" -eq 1 ] 40 | } 41 | 42 | @test "freset select commit" { 43 | run select_commit 44 | [[ "${output}" =~ "reset freset_commit --mixed" ]] 45 | } 46 | 47 | @test "freset select files" { 48 | run select_files 49 | [[ "${output}" =~ "reset" ]] 50 | [[ "${output}" =~ "freset_file" ]] 51 | } 52 | -------------------------------------------------------------------------------- /tests/fstash.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | setup() { 4 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 5 | } 6 | 7 | help() { 8 | bash "${BATS_TEST_DIRNAME}"/../dotbare fstash -h 9 | } 10 | 11 | invalid_option() { 12 | bash "${BATS_TEST_DIRNAME}"/../dotbare fstash -w 13 | } 14 | 15 | stash_file() { 16 | bash "${BATS_TEST_DIRNAME}"/../dotbare fstash -s 17 | } 18 | 19 | stash_delete() { 20 | bash "${BATS_TEST_DIRNAME}"/../dotbare fstash --delete --yes 21 | } 22 | 23 | stash_apply() { 24 | bash "${BATS_TEST_DIRNAME}"/../dotbare fstash --yes 25 | } 26 | 27 | @test "fstash help" { 28 | run help 29 | [ "${status}" -eq 0 ] 30 | [ "${lines[0]}" = "Usage: dotbare fstash [-h] [-s] [-d] [-p] ..." ] 31 | } 32 | 33 | @test "fstash invalid option" { 34 | run invalid_option 35 | [ "${status}" -eq 1 ] 36 | [ "${lines[0]}" = "Invalid option: -w" ] 37 | } 38 | 39 | @test "fstash stash select file" { 40 | run stash_file 41 | [[ "${output}" =~ "stash" ]] 42 | [[ "${output}" =~ "fstash_select" ]] 43 | } 44 | 45 | @test "fstash stash delete" { 46 | run stash_delete 47 | [[ "${output}" =~ "stash drop fstash_delete" ]] 48 | } 49 | 50 | @test "fstash apply stash" { 51 | run stash_apply 52 | [[ "${output}" =~ "stash apply fstash_apply" ]] 53 | } 54 | -------------------------------------------------------------------------------- /tests/fstat.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | help() { 4 | bash "${BATS_TEST_DIRNAME}"/../dotbare fstat -h 5 | } 6 | 7 | invalid_option() { 8 | bash "${BATS_TEST_DIRNAME}"/../dotbare fstat -p 9 | } 10 | 11 | no_modify() { 12 | bash "${BATS_TEST_DIRNAME}"/../dotbare fstat 13 | } 14 | 15 | @test "fstat help" { 16 | run help 17 | [ "${status}" -eq 0 ] 18 | [ "${lines[0]}" = "Usage: dotbare fstat [-h] ..." ] 19 | } 20 | 21 | @test "fstat invalid option" { 22 | run invalid_option 23 | [ "${status}" -eq 1 ] 24 | [ "${lines[0]}" = "Invalid option: -p" ] 25 | } 26 | 27 | @test "fstat run no modify file" { 28 | run no_modify 29 | [ "${status}" -eq 0 ] 30 | } 31 | -------------------------------------------------------------------------------- /tests/funtrack.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | setup() { 4 | export PATH="${BATS_TEST_DIRNAME}:$PATH" 5 | } 6 | 7 | help() { 8 | bash "${BATS_TEST_DIRNAME}"/../dotbare funtrack -h 9 | } 10 | 11 | invalid_option() { 12 | bash "${BATS_TEST_DIRNAME}"/../dotbare funtrack -p 13 | } 14 | 15 | untrack_file() { 16 | bash "${BATS_TEST_DIRNAME}"/../dotbare funtrack --yes 17 | } 18 | 19 | temp_untrack() { 20 | bash "${BATS_TEST_DIRNAME}"/../dotbare funtrack --yes -t 21 | } 22 | 23 | resume_track() { 24 | bash "${BATS_TEST_DIRNAME}"/../dotbare funtrack --yes --resume 25 | } 26 | 27 | @test "funtrack help" { 28 | run help 29 | [ "${status}" -eq 0 ] 30 | [ "${lines[0]}" = "Usage: dotbare funtrack [-h] [-t] [-r] [-y] ..." ] 31 | } 32 | 33 | @test "funtrack invalid option" { 34 | run invalid_option 35 | [ "${status}" -eq 1 ] 36 | [ "${lines[0]}" = "Invalid option: -p" ] 37 | } 38 | 39 | @test "funtrack untrack file" { 40 | run untrack_file 41 | [[ "${output}" =~ "rm --cached" ]] 42 | [[ "${output}" =~ "funtrack_file" ]] 43 | } 44 | 45 | @test "funtrack temp untrack" { 46 | run temp_untrack 47 | [[ "${output}" =~ "update-index --assume-unchanged" ]] 48 | [[ "${output}" =~ "funtrack_file" ]] 49 | } 50 | 51 | @test "funtrack resume track" { 52 | run resume_track 53 | [[ "${output}" =~ "update-index --no-assume-unchanged" ]] 54 | [[ "${output}" =~ "funtrack_file" ]] 55 | } 56 | -------------------------------------------------------------------------------- /tests/fupgrade.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | help() { 4 | bash "${BATS_TEST_DIRNAME}"/../dotbare fupgrade -h 5 | } 6 | 7 | invalid_option() { 8 | bash "${BATS_TEST_DIRNAME}"/../dotbare fupgrade -p 9 | } 10 | 11 | upgrade() { 12 | bash "${BATS_TEST_DIRNAME}"/../dotbare fupgrade 13 | } 14 | 15 | @test "fupgrade help" { 16 | run help 17 | [ "${status}" -eq 0 ] 18 | [ "${lines[0]}" = "Usage: dotbare fupgrade [-h] ..." ] 19 | } 20 | 21 | @test "fupgrade invliad option" { 22 | run invalid_option 23 | [ "${status}" -eq 1 ] 24 | [ "${lines[0]}" = "Invalid option: -p" ] 25 | } 26 | 27 | @test "fupgrade upgrade" { 28 | skip 29 | run upgrade 30 | [ "${status}" -eq 0 ] 31 | [ "${lines[0]}" = "Updating dotbare ..." ] 32 | } 33 | -------------------------------------------------------------------------------- /tests/fzf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # This script is for mocking fzf for testing, 4 | # it will stop fzf for goin into a interactive mode 5 | # 6 | # usage: 7 | # export PATH="${BATS_TEST_DIRNAME}:$PATH" 8 | 9 | if [[ "$*" =~ '--multi --preview ' ]] && [[ "$*" =~ "tree -L 1 -C --dirsfirst {}" ]]; then 10 | # dotbare fadd --dir -- "./fadd.bats" @test "fadd stage selected dir" 11 | echo "fadd_stage_dir" 12 | elif [[ "$*" =~ '--multi --preview' ]] && [[ "$*" =~ "preview.sh {}" ]]; then 13 | # dotbare fadd -f -- "./fadd.bats" @test "fadd stage selected file" 14 | echo "fadd_stage_file" 15 | elif [[ "$*" =~ '--header=select files to stage' ]] && [[ "$*" =~ "diff HEAD --color=always" ]]; then 16 | # dotbare fadd -- "./fadd.bats" @test "fadd stage modified files" 17 | echo "-- fadd_stage_modified" 18 | elif [[ "$*" =~ "--no-multi --header=select a branch to checkout" ]]; then 19 | # dotbare fcheckout --branch -- "./fcheckout.bats" @test "fcheckout branch" 20 | echo "fcheckout_branch" 21 | elif [[ "$*" =~ "--header=select a commit to checkout" ]] && [[ "$*" =~ "show --color" ]]; then 22 | # dotbare fcheckout --c -- "./fcheckout.bats" @test "fcheckout commit" 23 | echo "fcheckout_commit" 24 | elif [[ "$*" =~ "--header=select files to checkout version in HEAD" ]] && [[ "$*" =~ "diff HEAD --color=always" ]]; then 25 | # dotbare fcheckout -y -- "./fcheckout.bats" @test "fcheckout modified" 26 | echo "-- fcheckout_modified" 27 | elif [[ "$*" =~ '--header=select the target commit' ]] && [[ "$*" =~ "diff --color" ]]; then 28 | # dotbare fcheckout --yes -s -- "./fcheckout.bats" @test "fcheckout select" 29 | echo "fcheckout_select_commitdiff" 30 | elif [[ "$*" =~ '--header=select files to checkout' ]] && [[ "$*" =~ "preview.sh ${DOTBARE_TREE}/{}" ]]; then 31 | # dotbare fcheckout --yes -s -- "./fcheckout.bats" @test "fcheckout select" 32 | echo "fcheckout_select_gitfile" 33 | elif [[ "$*" =~ "--header=select a commit to edit --no-multi" ]] && [[ "$*" =~ "show --color=always" ]]; then 34 | # dotbare fedit --commit -- "./fedit.bats" @test "fedit edit commits" 35 | echo "fedit_commits" 36 | elif [[ "$*" =~ "--header=select files to edit" ]]; then 37 | # dotbare fedit -- "./fedit.bats" @test "fedit edit files" 38 | echo "fedit_files" 39 | elif [[ "$*" =~ '--header=select the target commit --no-multi' ]] && [[ "$*" =~ "show --color" ]]; then 40 | # dotbare freset --commit -y -- "./freset.bats" @test "freset select commit" 41 | echo "freset_commit" 42 | elif [[ "$*" =~ "--header=select files to unstage" ]] && [[ "$*" =~ "diff HEAD --color=always" ]]; then 43 | # dotbare freset -- "./freset.bats" @test "freset select files" 44 | echo "-- freset_file" 45 | elif [[ "$*" =~ "--no-multi --header=commit --flog_reset" ]]; then 46 | # dotbare flog -- "./flog.bats" @test "flog checkout routing" 47 | echo "exit" 48 | elif [[ "$*" =~ '--header=select a commit' ]] && [[ "$*" =~ "show --color" ]]; then 49 | # dotbare flog --reset -y -- "./flog.bats" @test "flog reset" 50 | echo "--flog_reset" 51 | elif [[ "$*" =~ "--header=select files to untrack" ]] && [[ "$*" =~ "preview.sh ${DOTBARE_TREE}/{}" ]]; then 52 | # dotbare funtrack -- "./funtrack.bats" @test "funtrack untrack file" 53 | echo "funtrack_file" 54 | elif [[ "$*" =~ '--header=select files to add to a stash' ]] && [[ "$*" =~ "diff HEAD --color=always" ]]; then 55 | # dotbare fstash -s -- "./fstash.bats" @test "fstash stash select file" 56 | echo "-- fstash_select" 57 | elif [[ "$*" =~ '--header=select stash to delete' ]] && [[ "$*" =~ "show -p __ --color=always" ]]; then 58 | # dotbare fstash --delete -- "./fstash.bats" @test "fstash stash delete" 59 | echo "fstash_delete" 60 | elif [[ "$*" =~ '--header=select stash to apply' ]] && [[ "$*" =~ "show -p __ --color=always" ]]; then 61 | # dotbare fstash -- "./fstash.bats" @test "fstash apply stash" 62 | echo "fstash_apply" 63 | else 64 | echo "$@" 65 | fi 66 | -------------------------------------------------------------------------------- /tests/git: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # This script is for mocking git during unit test, 4 | # used to mock all the git calls. 5 | # 6 | # usage: 7 | # export PATH="${BATS_TEST_DIRNAME}:$PATH" 8 | 9 | echo "$@" 10 | -------------------------------------------------------------------------------- /tests/set_variable.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | setup() { 4 | source "${BATS_TEST_DIRNAME}"/../helper/set_variable.sh 5 | } 6 | 7 | @test "env check env var" { 8 | [ "${DOTBARE_DIR}" = "$HOME/.cfg/" ] 9 | [ "${DOTBARE_TREE}" = "$HOME" ] 10 | [ "${DOTBARE_BACKUP}" = "$HOME/.local/share/dotbare" ] 11 | } 12 | 13 | @test "env check fzf var" { 14 | [ -n "${DOTBARE_KEY}" ] 15 | [ -n "${FZF_DEFAULT_OPTS}" ] 16 | [ -n "${DOTBARE_VERSION}" ] 17 | } 18 | -------------------------------------------------------------------------------- /tests/shellcheck.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # run shellcheck against all scripts 4 | 5 | set -e 6 | 7 | mydir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 8 | cd "${mydir}"/../ 9 | 10 | scripts=() 11 | while IFS= read -r -d $'\0' line; do 12 | scripts+=("$line") 13 | done < <( 14 | find \ 15 | dotbare \ 16 | helper/* \ 17 | scripts/* \ 18 | tests/shellcheck.sh \ 19 | -type f \ 20 | -print0 21 | ) 22 | 23 | shellcheck -e SC1091,SC1090 "${scripts[@]}" 24 | shellcheck -e SC1091 --shell=bash "dotbare.plugin.bash" 25 | shellcheck --shell=bash "pkg/completion/bash/dotbare" 26 | # \shellcheck does not have zsh support yet, hence using bash for now 27 | shellcheck -e SC2034,SC2277,SC2269 --shell=bash "dotbare.plugin.zsh" 28 | shellcheck -e SC2034,SC2269 --shell=bash "pkg/completion/zsh/_dotbare" 29 | 30 | exit $? 31 | -------------------------------------------------------------------------------- /tests/tree: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # This script is for mocking tree during unit test, 4 | # just that we don't need install tree during different 5 | # test environment. 6 | # 7 | # usage: 8 | # export PATH="${BATS_TEST_DIRNAME}:$PATH" 9 | 10 | echo "$@" 11 | --------------------------------------------------------------------------------