Compare commits

...

107 Commits

Author SHA1 Message Date
00ba5ec50b merge upstream/master 2022-02-10 08:59:46 +01:00
Wilhelmina Drengwitz
ff6af425e2 Merge pull request #296 from Lotterleben/add_ruby_req_doc
README.md: add remark that some commands don't work w/o ruby
2021-07-26 11:34:56 -07:00
Wilhelmina Drengwitz
759c70d9cb Merge pull request #310 from yhpark/gs-fix
`gs` fixes
2021-04-19 12:48:09 -04:00
Yeonghoon Park
27e702bb7a gs fixes 2021-04-14 17:53:54 +09:00
Wilhelmina Drengwitz
0a687dcfe5 Merge pull request #307 from telzhov/master
Replaced calls to '_git' wrapper with its contents, '__git_wrap__git_…
2021-01-05 12:34:37 -05:00
telzhov
ad6bfdda3d Replaced calls to '_git' wrapper with its contents, '__git_wrap__git_main'
Since '_git' has been removed in git 2.30
2021-01-02 23:33:39 +03:00
Wilhelmina Drengwitz
4f1e421652 Merge pull request #304 from yhpark/switch_restore
Add aliases for git switch `gsw` / git restore `grt`
2020-09-06 13:45:50 -07:00
Arthas Park
9187f1b04c Add aliases for git switch (gsw) / git restore (grt) 2020-09-06 01:49:39 +09:00
Wilhelmina Drengwitz
6ffbc369b9 Merge pull request #302 from jeffbyrnes/tighten-up-shell-shortcuts
Avoid running ll code if its not used
2020-07-29 17:35:33 -07:00
Jeff Byrnes
800b1b1e0a Avoid running ll code if its not used
Prior to this, if $shell_ls_aliases_enabled="false", this code would
still run, but unnecessarily.
2020-07-29 17:48:53 -04:00
Wilhelmina Drengwitz
e7e9b2bb47 Merge pull request #301 from m-rey/fix_zshrc_path
Use ZDOTDIR env variable for path to .zshrc
2020-03-10 15:03:17 -07:00
Martin Rey
1a7d86fdbc Use ZDOTDIR env variable for path to .zshrc
.zshrc can be found at "~/.zshrc", when ZDOTDIR is not set.
If ZDOTDIR is set, .zshrc is in "${ZDOTDIR}/.zshrc".
Using parameter expansion, the hardcoded path can be replaced with
"${ZDOTDIR:-$HOME}/.zshrc". That way, it'll use the value in
ZDOTDIR when set and the value in HOME when not.
This thus mirrors the usage of ZDOTDIR in zsh and makes the code
more fexible.
2020-03-09 22:25:17 +01:00
Lotte Steenbrink
689c8e29e4 README.md: add remark that some commands don't work w/o ruby 2019-10-15 21:27:58 +02:00
Wilhelmina Drengwitz
8f5693f345 Merge pull request #292 from jawshooah/patch-1
Wrap more common shell commands by default
2019-08-29 10:37:47 -04:00
Josh Hagins
2c3b15e13c Wrap more common shell commands by default 2019-08-28 15:01:01 -04:00
Wilhelmina Drengwitz
134d101783 Merge pull request #289 from dump247/master
Fix infinite loop when parent directory does not exist
2019-05-16 13:31:14 -04:00
Cory Thomas
3c97507b3e Make variables local instead of global 2019-05-15 16:33:10 -05:00
Cory Thomas
cebddb8aba Fix infinite loop when parent directory does not exist
resolves #241
2019-05-15 16:25:14 -05:00
Wilhelmina Drengwitz
6b69a5e4d5 Merge pull request #286 from dishbreak/patch-1
Update README.md
2019-02-26 20:23:38 -05:00
Vishal Kotcherlakota
24f96762b1 Update README.md
It took me a minute to figure out how to use the git_index feature. Hopefully this documentation update helps the next person!
2019-02-26 11:05:47 -08:00
Nathan Broadbent
dec2fff0bf Support coreutils on Mac, which provides a greadlink command that supports the -f option (brew install coreutils) 2018-12-19 20:05:05 +07:00
Nathan Broadbent
5bc863284b Change maxdepth to 3 in _find_git_repos (c --rebuild was taking too long) 2018-12-18 21:28:02 +07:00
Wilhelmina Drengwitz
77e5e3776c Merge pull request #281 from ghthor/fix-ci-zsh-install
Add apkg repository update before install
2018-10-17 23:31:44 -04:00
Willa Drengwitz
888a53f1ba Add apkg repository update before install 2018-10-16 18:56:05 -04:00
Wilhelmina Drengwitz
630fd8f834 Merge pull request #280 from HaleTom/fix-gb
Fix #277 - gb doesn't work with no arguments
2018-10-09 12:10:33 -04:00
Tom "Ravi" Hale
d15ece1d99 _scmb_git_branch_shortcuts: quote $@ inside ruby heredoc 2018-10-09 12:12:08 +07:00
Wilhelmina Drengwitz
7152788516 Merge pull request #263 from HaleTom/quote-filenames
Fix #167, #202, #204, #274 and a bunch of other goodies
2018-09-29 08:01:30 -04:00
Wilhelmina Drengwitz
a8cf40722d Merge branch 'master' into quote-filenames 2018-09-28 13:12:38 -04:00
Nathan Broadbent
e5971cfdd5 Added keyboard shortcut to add all changes to the previous commit (Ctrl+x, z) 2018-09-26 23:15:12 +07:00
Nathan Broadbent
8233abd23f Save/restore the git commit message in case a git pre-commit hook fails. Also rename the APPEND var to GIT_COMMIT_MSG_SUFFIX. 2018-09-26 23:08:00 +07:00
Nathan Broadbent
1f60a87a77 Figured out how to set image width in README 2018-09-24 18:16:24 +07:00
Nathan Broadbent
c76a580b97 Fix image path 2018-09-24 18:12:26 +07:00
Nathan Broadbent
7e32c12f6c Fix max-width of image in README 2018-09-24 18:09:48 +07:00
Nathan Broadbent
5530e693b3 Added ~/.staff_sym emoji, and some docs to the README 2018-09-24 18:06:52 +07:00
Tom "Ravi" Hale
29db632289 .travis.yml: add sudo: required
Avoid Travis CI error for zsh on linux:

   $ ./test/support/travisci_deps.sh
   This job is running on container-based infrastructure, which does not
   allow use of 'sudo', setuid, and setgid executables.  If you require
   sudo, add 'sudo: required' to your .travis.yml
2018-09-18 17:03:01 +07:00
Tom "Ravi" Hale
48302bcd8c Be compatible with shells of Ubuntu 14.04 2018-09-18 17:03:01 +07:00
Wilhelmina Drengwitz
83467edac0 Merge pull request #273 from jeffbyrnes/add-gmt-alias
Add alias & default shortcut for `git mergetool`
2018-09-17 11:25:31 -04:00
Tom "Ravi" Hale
e5da83665a bin_path(): use builtin commands and avoid which 2018-09-14 19:58:25 +07:00
Tom "Ravi" Hale
f85b9a4727 git_show_affected_files: make $f local 2018-09-14 19:58:25 +07:00
Tom "Ravi" Hale
4adf771492 Ensure file ordering matches in both invocations of ls 2018-09-14 19:58:25 +07:00
Tom "Ravi" Hale
e46a7c3309 ls_with_file_shortcuts: fail rather than create incorrect variables
Removes the danger from issue #274.

The proper fix will need to address issue #260.
2018-09-14 19:58:09 +07:00
Tom "Ravi" Hale
80ec1ad2ad Replace built-in shell array quoting with printf %q 2018-09-12 17:57:46 +07:00
Tom "Ravi" Hale
21d155776a Allow run_tests.sh to be executed from anywhere 2018-09-12 15:44:51 +07:00
Jeff Byrnes
8761a4758b Add alias & default shortcut for git mergetool
Provides parity with the `gdt` alias for `git difftool`
2018-09-11 10:36:34 -04:00
Wilhelmina Drengwitz
d1723709f1 Merge pull request #269 from ghthor/revert-status-shortcuts
Revert to legacy status shortcuts ruby script
2018-09-05 12:30:00 -04:00
Willa Drengwitz
1a9411dd4a Revert to legacy status shortcuts ruby script 2018-09-05 12:24:14 -04:00
Tom "Ravi" Hale
a580c53004 ls_with_file_shortcuts: print error to STDERR 2018-09-02 11:34:33 +07:00
Tom "Ravi" Hale
a6eeebfa91 shell_shortcuts.sh: remove unnecessary subshell 2018-09-02 11:34:32 +07:00
Tom "Ravi" Hale
86d9d4b189 shell_shortcuts.sh: fix quoting 2018-09-02 11:34:32 +07:00
Tom "Ravi" Hale
695941b596 Add tests for exec_scmb_expand_args() 2018-09-02 11:34:32 +07:00
Tom "Ravi" Hale
a8092bffd9 Clean up ls_with_file_shortcuts() shwordsplit tests 2018-09-02 11:34:32 +07:00
Tom "Ravi" Hale
f55ce1e6a3 test_ls_with_file_shortcuts: clean up temp files 2018-09-02 11:34:32 +07:00
Tom "Ravi" Hale
0b5a29bbd6 Invoke readlink -f in a way which can succeed 2018-09-02 11:34:32 +07:00
Tom "Ravi" Hale
5a8c2fec12 assert(Not)?Includes: check for failure of _includes
Call _includes and then check its return value.

shunit2 uses the exit code to test, not a string of 0 or 1 as was done
previously.
2018-09-02 11:32:02 +07:00
Tom "Ravi" Hale
ed63b41182 test_helper: Don't clobber global name/email config
Config included by gitconfig [include] is not considered global.

Test git config values without --global to include local config as well.

Change only local config (not global) if needed.
2018-09-02 11:28:47 +07:00
Tom "Ravi" Hale
b193438ca1 shell_shortcuts_test: Unset $QUOTING_STYLE for predictable ls output 2018-09-02 11:28:47 +07:00
Tom "Ravi" Hale
73ed8cb53e scmb_expand_args: return an array to fix quoting issues 2018-09-02 11:28:47 +07:00
Tom "Ravi" Hale
fb7d227c30 Add _safe_eval: quote $@ elements before eval 2018-09-02 11:28:19 +07:00
Tom "Ravi" Hale
d5c60b2cc5 git_status_shortcuts: don't clobber $IFS 2018-09-01 20:19:57 +07:00
Tom "Ravi" Hale
3a5b7a685a _print_path: remove unnecessary pipeline 2018-09-01 20:14:36 +07:00
Tom "Ravi" Hale
5f286eaaaa Quote arrays to avoid splitting by $IFS 2018-09-01 20:14:36 +07:00
Wilhelmina Drengwitz
8a326c2505 Merge pull request #262 from ghthor/refactor_of_git_status
Refactor of git status, Closes #132
2018-08-31 16:11:14 -04:00
Willa Drengwitz
750697e925 Add quotes around files with spaces 2018-08-31 16:02:39 -04:00
Willa Drengwitz
fc679a06ac Update strip color perl command 2018-08-31 13:53:51 -04:00
Willa Drengwitz
f0ef9b06f6 Add back too status max files check 2018-08-31 13:51:34 -04:00
Willa Drengwitz
e789faa1fd Merge remote-tracking branch 'origin/master' into refactor_of_git_status 2018-08-31 13:24:24 -04:00
Nathan Broadbent
e8a5f775d1 Use "^M" on Zsh and "\n" on Bash 2018-09-01 00:22:33 +07:00
Willa Drengwitz
0acc0223a5 Add legacy status script 2018-08-31 13:22:16 -04:00
Nathan Broadbent
e6b1785910 Revert "Use ^M instead of" - Stick with "\n" for now so that Ctrl + x + space works on bash
This reverts commit 1f3b8a6b11.
2018-08-31 23:53:42 +07:00
Nathan Broadbent
7fcd70adc2 Rename README.markdown => README.md 2018-08-31 23:45:57 +07:00
Nathan Broadbent
f59a255c9c Remove video and GIF from README 2018-08-31 23:45:40 +07:00
Wilhelmina Drengwitz
ce2d6024ac Merge pull request #259 from ghthor/add-git-grep-aliases
[PATCH] Add grep_shortcuts
2018-08-31 09:36:45 -04:00
Wilhelmina Drengwitz
1169402e62 Merge pull request #215 from baumhoto/master
changed alias "gls" due to issue with zsh
2018-08-31 09:35:51 -04:00
David Lee
7189656854 [PATCH] Add grep_shortcuts
Closes #125, Thanks David Lee!
2018-08-31 09:33:37 -04:00
Wilhelmina Drengwitz
413ca62d5c Merge pull request #234 from ghthor/fix-tests
Fix tests
2018-08-31 09:12:18 -04:00
Wilhelmina Drengwitz
77916f056a Add bash & zsh compatible way to resolve abs exe paths 2018-08-31 09:09:46 -04:00
Wilhelmina Drengwitz
6143b31a11 Merge pull request #258 from ghthor/osx-testing
OSX/Darwin testing and compatibility - Retest
2018-08-31 09:03:34 -04:00
Willa Drengwitz
f5850830fa Fix tr illegal command 2018-08-31 09:01:06 -04:00
Willa Drengwitz
89cf0eb6ad Run shfmt 2018-08-31 08:58:41 -04:00
Willa Drengwitz
d0c8329137 Fix sorting order 2018-08-31 08:58:23 -04:00
Willa Drengwitz
a3ff809cbe Fix ordering to match declare order 2018-08-31 07:56:58 -04:00
Willa Drengwitz
e6363ac955 Merge remote-tracking branch 'mroth/osx-testing' into osx-testing 2018-08-31 07:48:09 -04:00
Wilhelmina Drengwitz
87f848b07f Merge pull request #257 from ghthor/fix-for-uninstall
Fix uninstall for osx
2018-08-31 07:34:51 -04:00
Willa Drengwitz
744cae46d6 Fix uninstall for osx 2018-08-31 07:29:44 -04:00
Wilhelmina Drengwitz
92689b3a19 Add links to alternatives 2018-08-31 07:13:23 -04:00
Wilhelmina Drengwitz
975e423b80 Merge pull request #253 from HaleTom/no_trailing_--_in_aliases
Remove "--" from end of aliases
2018-08-24 10:54:38 -04:00
Tom "Ravi" Hale
70b4e62bb0 Remove -- from end of aliases 2018-08-18 14:35:43 +07:00
Wilhelmina Drengwitz
8966fc9585 Merge pull request #251 from HaleTom/fix-sed-test-pipefail
Fix #250 - Avoid test with no arguments and unnecessary subshell
2018-08-17 02:04:02 -04:00
Tom "Ravi" Hale
77b1717008 Avoid test with no arguments and unnecessary subshell 2018-08-17 12:49:07 +07:00
Wilhelmina Drengwitz
4c95bafbd3 Merge pull request #246 from michaelmior/fix-newline
Use ^M instead of  for newlines
2018-07-05 16:59:55 -04:00
Michael Mior
1f3b8a6b11 Use ^M instead of
for newlines
2018-07-05 16:21:02 -04:00
Wilhelmina Drengwitz
7f635b0e42 Merge pull request #249 from nqb/patch-1
replace 'ge' by `ge`
2018-06-27 13:08:27 -04:00
Nicolas Quiniou-Briand
ca5c15d4a0 replace 'ge' by ge 2018-06-27 08:44:57 -04:00
Tobias Baumhöver
b5606ed897 changed alias for git_log_stat_alias from gls to glst due to issue with recent zsh update 2016-11-01 13:33:50 +01:00
Matthew Rothenberg
c6b9c398c8 temp before_script to debug sort order on travis
I tested manually on OSX and linux, but lets make sure the same thing is
true on travis-ci builds.
2014-10-20 15:16:04 -04:00
Matthew Rothenberg
9a9b6104e2 Compatibility fix for Design Assets Management
design.sh uses `readlink -m` to determine canonical path of git dir,
which is not available on all *nix systems (including Darwin).

Instead, use `pwd -P` to get canonical directory path in a more
cross-platform compatible way.

This is a change to an actual script rather than just a test, and it
should make the Design Assets Management functionality of scm_breeze
now function properly on MacOSX.
2014-10-16 17:20:49 -04:00
Matthew Rothenberg
c234916b2b scripts should exit rather than return
some shells are pickier about this.  darwin uses a newer version of sh
that complains about it.  this is the ‘proper’ behavior in either
scenario.
2014-10-16 17:08:29 -04:00
Matthew Rothenberg
ae4b93f52f declare original location of cmds
The previous tests assumed default locations for all commands, however
they do not exist in the same place on all *nixes.  I encountered this
when the test was failing on MacOSX where it was expected hardcoded
`/bin/sed` when in fact the code was identifying the correct local
expansion of `/usr/bin/sed`.

To make this test more robust, it now checks for the original location
of all cmds and uses that in its expansion tests for
`test_shell_command_wrapping()`.
2014-10-16 17:05:43 -04:00
Matthew Rothenberg
1cd162434f Make sure we have physical path back from mktemp
Darwin actually symlinks /var inside /private, but mktemp reports back
the logical pathat time of file creation.  So make sure we always get
the full physical path to be absolutely certain when doing comparisons
later, because thats how the Ruby status_shortcuts.rb script is going to
obtain them.
2014-10-16 17:05:43 -04:00
Matthew Rothenberg
b2d86a16b2 use perl instead of sed -r to strip colors in test
`sed -r` is not present on some BSD based systems, including MacOSX
Darwin.  perl is standard pretty much everywhere, so this a more
reliable way to test.

Since this is only used for tests, any performance differences
should not matter significantly.
2014-10-16 15:31:12 -04:00
Matthew Rothenberg
b395596496 dont use grep -P for cross-platform compatibility
`grep -P` gives access to the PCRE matching engine, which is nice,
however, the version of grep shipped on many BSD systems (including
Darwin) does not have this flag.

Currently, `grep -P` was being used in the `_includes()` test helper.

For cross platform compatibility in tests, do not rely upon this option.
Luckily, all existing tests seem to work fine without it already!
2014-10-16 15:26:34 -04:00
Matthew Rothenberg
f056d28b2e remove redundant test envs
they were just there when we were making sure the env variable shell
selection was working properly in all cases, now that we know it is,
they can be removed.
2014-10-16 15:25:58 -04:00
Matthew Rothenberg
e7c56c7647 only install zsh on boxes that need it
don’t bother on macosx (preinstalled) or if the test matrix for that
box isn’t going to be testing in zsh.

this should speed up test runs for most cases, and later we can define
fast_failure and not have to wait for the longer ones.
2014-10-16 15:25:58 -04:00
Matthew Rothenberg
b6fd7ae829 split tests up by shell for concurrency
More parallelism = faster tests.  Also better isolation for changes that
might only break on zsh or bash respectively.

This is defined via env variable, so someone running locally will have
all tests run sequentially as before.
2014-10-16 15:24:53 -04:00
Matthew Rothenberg
802f4987c3 set up multi-os testing in travis
Requires beta access, thankfully the travis gods have blessed us for the
main repo and my fork!

This should allow us to make sure scm_breeze operates reliably in both
Linux and BSD/Darwin, because there are small shell differences
(especially with default tools) that are causing errors I noticed on
MacOSX.
2014-10-16 15:23:10 -04:00
LFDM
fe1d4435a7 Refactor, commenting, polishing. 2014-01-29 22:53:20 +01:00
LFDM
33b561ebc1 status_shortcuts.rb completely rewritten 2014-01-29 21:05:24 +01:00
30 changed files with 1042 additions and 273 deletions

View File

@@ -1,3 +1,18 @@
script: ./run_tests.sh os:
- linux
- osx
env:
- TEST_SHELLS=bash
- TEST_SHELLS=zsh
sudo: required
install:
- ./test/support/travisci_deps.sh
before_script: before_script:
- sudo apt-get install zsh - echo -e "test_repo_11\ntest_repo_1" | sort
script:
- ./run_tests.sh

View File

@@ -11,9 +11,6 @@ your interaction with git. It integrates with your shell to give you numbered
file shortcuts, a repository index with tab completion, and many other useful file shortcuts, a repository index with tab completion, and many other useful
features. features.
![SCM Breeze Example Gif](http://i.imgur.com/3fD8cpo.gif)
- [Installation](#installation) - [Installation](#installation)
- [Usage](#usage) - [Usage](#usage)
- [File Shortcuts](#file-shortcuts) - [File Shortcuts](#file-shortcuts)
@@ -32,7 +29,7 @@ features.
```bash ```bash
git clone git://github.com/scmbreeze/scm_breeze.git ~/.scm_breeze git clone git://github.com/scmbreeze/scm_breeze.git ~/.scm_breeze
~/.scm_breeze/install.sh ~/.scm_breeze/install.sh
source ~/.bashrc # or source ~/.zshrc source ~/.bashrc # or source "${ZDOTDIR:-$HOME}/.zshrc"
``` ```
The install script creates required default configs and adds the following line The install script creates required default configs and adds the following line
@@ -40,13 +37,7 @@ to your `.bashrc` or `.zshrc`:
`[ -s "$HOME/.scm_breeze/scm_breeze.sh" ] && source "$HOME/.scm_breeze/scm_breeze.sh"` `[ -s "$HOME/.scm_breeze/scm_breeze.sh" ] && source "$HOME/.scm_breeze/scm_breeze.sh"`
**Note:** SCM Breeze performs much faster if you have ruby installed. **Note:** You need to install ruby for some SCM Breeze commands to work. This also improves performance. See [ruby-lang.org](https://www.ruby-lang.org/en/documentation/installation/) for installation information.
## Usage
<center><a href="http://www.youtube.com/watch?v=iKdp6uBfrvc"
target="_blank"><img src="http://i.imgur.com/l7aGG.png"></a></center>
### File Shortcuts ### File Shortcuts
@@ -114,7 +105,7 @@ $ gco 5
You can use these shortcuts with system commands by passing your command You can use these shortcuts with system commands by passing your command
through `exec_scmb_expand_args` (default alias is 'ge'): through `exec_scmb_expand_args` (default alias is `ge`):
```bash ```bash
@@ -190,8 +181,9 @@ doesn't need to 'learn' anything, and it can do SCM-specific stuff like:
The default alias for `git_index` is 'c', which might stand for 'code' The default alias for `git_index` is 'c', which might stand for 'code'
You will first need to configure your repository directory, and then build the You will first need to configure your repository directory by setting `GIT_REPO_DIR` in `~/.git.sbmrc`.
index:
Then, build the index:
```bash ```bash
$ c --rebuild $ c --rebuild
@@ -261,7 +253,7 @@ default base subdirectories are: Images, Backgrounds, Logos, Icons, Mockups,
and Screenshots. and Screenshots.
After you have changed these settings, remember to run `source ~/.bashrc` or After you have changed these settings, remember to run `source ~/.bashrc` or
`source ~/.zshrc`. `source "${ZDOTDIR:-$HOME}/.zshrc"`.
#### 2) Initialize design directories for your projects #### 2) Initialize design directories for your projects
@@ -332,7 +324,7 @@ Each feature is modular, so you are free to ignore the parts you don't want to
use. Just comment out the relevant line in `~/.scm_breeze/scm_breeze.sh`. use. Just comment out the relevant line in `~/.scm_breeze/scm_breeze.sh`.
**Note:** After changing any settings, you will need to run `source ~/.bashrc` **Note:** After changing any settings, you will need to run `source ~/.bashrc`
(or `source ~/.zshrc`) (or `source "${ZDOTDIR:-$HOME}/.zshrc"`)
I know we grow attached to the aliases we use every day, so I've made the alias I know we grow attached to the aliases we use every day, so I've made the alias
system completely customizable. You have two options when it comes to aliases: system completely customizable. You have two options when it comes to aliases:
@@ -359,6 +351,22 @@ as `gs` for the extended `git status`, and `ga` for the `git add` function.
If you already have an alias like `alias gco="git checkout"`, you can now type If you already have an alias like `alias gco="git checkout"`, you can now type
`gco 1` to checkout the first file in the output of SCM Breeze's `git status`. `gco 1` to checkout the first file in the output of SCM Breeze's `git status`.
## Custom emojis for username and "staff" group
The `ll` command adds numbered shortcuts to files, but another fun feature is replacing your
username and the "staff" group with custom emojis. You can set these in `~/.user_sym` and `~/.staff_sym`.
<img src="/docs/images/custom_user_and_staff_symbols.jpg" width="400" alt="Custom user and staff emojis">
Set your own emojis by running:
```bash
echo 🍀 > ~/.user_sym
echo 🖥 > ~/.staff_sym
```
I also like using `~/.user_sym` [in my Bash prompt](https://github.com/ndbroadbent/dotfiles/blob/master/bashrc/prompt.sh#L71).
## Notes about Tab Completion for Aliases ## Notes about Tab Completion for Aliases
@@ -406,3 +414,7 @@ SCMs.
***Enjoy!*** ***Enjoy!***
## Alternative Projects
1. https://github.com/shinriyo/breeze `fish` support
1. https://github.com/mroth/scmpuff static go binary

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

View File

@@ -34,10 +34,10 @@ git_alias="g"
# 1. 'SCM Breeze' functions # 1. 'SCM Breeze' functions
git_status_shortcuts_alias="gs" git_status_shortcuts_alias="gs"
git_add_shortcuts_alias="ga" git_add_shortcuts_alias="ga"
git_add_patch_alias="gap"
git_add_updated_alias="gau"
git_show_files_alias="gsf"
exec_scmb_expand_args_alias="ge" exec_scmb_expand_args_alias="ge"
git_show_files_alias="gsf"
git_commit_all_alias="gca"
git_grep_shortcuts_alias="gtrep"
# 2. Commands that handle paths (with shortcut args expanded) # 2. Commands that handle paths (with shortcut args expanded)
git_checkout_alias="gco" git_checkout_alias="gco"
git_checkout_branch_alias="gcb" git_checkout_branch_alias="gcb"
@@ -53,6 +53,7 @@ git_diff_file_alias="gdf"
git_diff_word_alias="gdw" git_diff_word_alias="gdw"
git_diff_cached_alias="gdc" git_diff_cached_alias="gdc"
git_difftool_alias="gdt" git_difftool_alias="gdt"
git_mergetool_alias="gmt"
# 3. Standard commands # 3. Standard commands
git_clone_alias="gcl" git_clone_alias="gcl"
git_fetch_alias="gf" git_fetch_alias="gf"
@@ -68,7 +69,8 @@ git_status_short_alias="gss"
git_clean_alias="gce" git_clean_alias="gce"
git_clean_force_alias="gcef" git_clean_force_alias="gcef"
git_add_all_alias="gaa" git_add_all_alias="gaa"
git_commit_all_alias="gca" git_add_patch_alias="gap"
git_add_updated_alias="gau"
git_commit_amend_alias="gcm" git_commit_amend_alias="gcm"
git_commit_amend_no_msg_alias="gcmh" git_commit_amend_no_msg_alias="gcmh"
git_commit_no_msg_alias="gch" git_commit_no_msg_alias="gch"
@@ -89,7 +91,7 @@ git_merge_only_fast_forward_alias="gmff"
git_cherry_pick_alias="gcp" git_cherry_pick_alias="gcp"
git_log_alias="gl" git_log_alias="gl"
git_log_all_alias="gla" git_log_all_alias="gla"
git_log_stat_alias="gls" git_log_stat_alias="glst"
git_log_graph_alias="glg" git_log_graph_alias="glg"
git_show_alias="gsh" git_show_alias="gsh"
git_show_summary="gsm" # (gss taken by git status short) git_show_summary="gsm" # (gss taken by git status short)
@@ -103,6 +105,8 @@ git_submodule_update_rec_alias="gsur"
git_top_level_alias="gtop" git_top_level_alias="gtop"
git_whatchanged_alias="gwc" git_whatchanged_alias="gwc"
git_apply_alias="gapp" git_apply_alias="gapp"
git_switch_alias="gsw"
git_restore_alias="grt"
# Hub aliases (https://github.com/github/hub) # Hub aliases (https://github.com/github/hub)
git_pull_request_alias="gpr" git_pull_request_alias="gpr"
@@ -113,7 +117,8 @@ git_pull_request_alias="gpr"
git_keyboard_shortcuts_enabled="true" git_keyboard_shortcuts_enabled="true"
git_commit_all_keys="\C-x " # CTRL+x, SPACE git_commit_all_keys="\C-x " # CTRL+x, SPACE
git_add_and_commit_keys="\C-xc" # CTRL+x, c git_add_and_commit_keys="\C-xc" # CTRL+x, c
git_commit_all_with_ci_skip_keys="\C-xv" # CTRL+x, v (Appends [ci skip] to commit message) git_commit_all_with_ci_skip_keys="\C-xv" # CTRL+x, v (Appends [ci skip] to message)
git_add_and_amend_commit_keys="\C-xz" # CTRL+x, z
# Shell Command Wrapping # Shell Command Wrapping
@@ -121,6 +126,6 @@ git_commit_all_with_ci_skip_keys="\C-xv" # CTRL+x, v (Appends [ci skip] to c
# Expand numbered args for common shell commands # Expand numbered args for common shell commands
shell_command_wrapping_enabled="true" shell_command_wrapping_enabled="true"
# Here you can tweak the list of wrapped commands. # Here you can tweak the list of wrapped commands.
scmb_wrapped_shell_commands="vim emacs gedit cat rm cp mv ln cd" scmb_wrapped_shell_commands="vim emacs gedit cat rm cp mv ln cd ls less subl code"
# Add numbered shortcuts to output of ls -l, just like 'git status' # Add numbered shortcuts to output of ls -l, just like 'git status'
shell_ls_aliases_enabled="true" shell_ls_aliases_enabled="true"

View File

@@ -10,10 +10,10 @@ fi
# This loads SCM Breeze into the shell session. # This loads SCM Breeze into the shell session.
exec_string="[ -s \"$HOME/.scm_breeze/scm_breeze.sh\" ] && source \"$HOME/.scm_breeze/scm_breeze.sh\"" exec_string="[ -s \"$HOME/.scm_breeze/scm_breeze.sh\" ] && source \"$HOME/.scm_breeze/scm_breeze.sh\""
# Add line to bashrc, zshrc, and bash_profile if not already present. # Add line to bashrc and bash_profile if not already present.
added_to_profile=false added_to_profile=false
already_present=false already_present=false
for rc in bashrc zshrc bash_profile; do for rc in bashrc bash_profile; do
if [ -s "$HOME/.$rc" ]; then if [ -s "$HOME/.$rc" ]; then
if grep -q "$exec_string" "$HOME/.$rc"; then if grep -q "$exec_string" "$HOME/.$rc"; then
printf "== Already installed in '~/.$rc'\n" printf "== Already installed in '~/.$rc'\n"
@@ -26,13 +26,27 @@ for rc in bashrc zshrc bash_profile; do
fi fi
done done
# Add line to .zshrc if not aleady present.
# When set, the ZDOTDIR environment variable states the directory zshrc is in.
# If not set, HOME environment variable is used as fallback.
if [ -s "${ZDOTDIR:-$HOME}/.zshrc" ]; then
if grep -q "$exec_string" "${ZDOTDIR:-$HOME}/.zshrc"; then
printf "== Already installed in '${ZDOTDIR:-$HOME}/.zshrc'\n"
already_present=true
else
printf "\n$exec_string\n" >> "${ZDOTDIR:-$HOME}/.zshrc"
printf "== Added SCM Breeze to '${ZDOTDIR:-$HOME}/.zshrc'\n"
already_present=true
fi
fi
# Load SCM Breeze update scripts # Load SCM Breeze update scripts
source "$scmbDir/lib/scm_breeze.sh" source "$scmbDir/lib/scm_breeze.sh"
# Create '~/.*.scmbrc' files from example files # Create '~/.*.scmbrc' files from example files
_create_or_patch_scmbrc _create_or_patch_scmbrc
if [ "$added_to_profile" = true ] || [ "$already_present" = true ]; then if [ "$added_to_profile" = true ] || [ "$already_present" = true ]; then
echo "== SCM Breeze Installed! Run 'source ~/.bashrc || source ~/.bash_profile' or 'source ~/.zshrc'" echo "== SCM Breeze Installed! Run 'source ~/.bashrc || source ~/.bash_profile' or 'source \"${ZDOTDIR:-$HOME}/.zshrc\"'"
echo " to load SCM Breeze into your current shell." echo " to load SCM Breeze into your current shell."
else else
echo "== Error:" echo "== Error:"

View File

@@ -23,7 +23,7 @@
# Add ignore rule to .git/info/exclude if not already present # Add ignore rule to .git/info/exclude if not already present
_design_add_git_exclude(){ _design_add_git_exclude(){
local git_dir="$(cd $1 && readlink -m $(git rev-parse --git-dir))" local git_dir="$(cd $1 && cd `git rev-parse --git-dir` && pwd -P)"
if [ -e "$git_dir/info/exclude" ] && ! $(grep -q "$project_design_dir" "$git_dir/info/exclude"); then if [ -e "$git_dir/info/exclude" ] && ! $(grep -q "$project_design_dir" "$git_dir/info/exclude"); then
echo "$project_design_dir" >> "$git_dir/info/exclude" echo "$project_design_dir" >> "$git_dir/info/exclude"
fi fi
@@ -34,7 +34,7 @@ design() {
local project=`basename $(pwd)` local project=`basename $(pwd)`
local all_project_dirs="$design_base_dirs $design_av_dirs" local all_project_dirs="$design_base_dirs $design_av_dirs"
# Ensure design dir contains all subdirectories # Ensure design dir contains all subdirectories
IFS=$' \t\n' local IFS=$' \t\n'
# Create root design dirs # Create root design dirs
for dir in $design_ext_dirs; do mkdir -p "$root_design_dir/$dir"; done for dir in $design_ext_dirs; do mkdir -p "$root_design_dir/$dir"; done
# Create project design dirs # Create project design dirs
@@ -102,6 +102,5 @@ design() {
printf "Invalid command.\n\n" printf "Invalid command.\n\n"
design design
fi fi
unset IFS
} }

View File

@@ -17,7 +17,7 @@ unalias git > /dev/null 2>&1
unset -f git > /dev/null 2>&1 unset -f git > /dev/null 2>&1
# Use the full path to git to avoid infinite loop with git function # Use the full path to git to avoid infinite loop with git function
export _git_cmd="$(\which git)" export _git_cmd="$(bin_path git)"
# Wrap git with the 'hub' github wrapper, if installed (https://github.com/defunkt/hub) # Wrap git with the 'hub' github wrapper, if installed (https://github.com/defunkt/hub)
if type hub > /dev/null 2>&1; then export _git_cmd="hub"; fi if type hub > /dev/null 2>&1; then export _git_cmd="hub"; fi
@@ -28,9 +28,9 @@ if type hub > /dev/null 2>&1; then export _git_cmd="hub"; fi
function git(){ function git(){
# Only expand args for git commands that deal with paths or branches # Only expand args for git commands that deal with paths or branches
case $1 in case $1 in
commit|blame|add|log|rebase|merge|difftool) commit|blame|add|log|rebase|merge|difftool|switch)
exec_scmb_expand_args "$_git_cmd" "$@";; exec_scmb_expand_args "$_git_cmd" "$@";;
checkout|diff|rm|reset) checkout|diff|rm|reset|restore)
exec_scmb_expand_args --relative "$_git_cmd" "$@";; exec_scmb_expand_args --relative "$_git_cmd" "$@";;
branch) branch)
_scmb_git_branch_shortcuts "${@:2}";; _scmb_git_branch_shortcuts "${@:2}";;
@@ -57,7 +57,7 @@ let COMP_CWORD+=1
local cur words cword prev local cur words cword prev
_get_comp_words_by_ref -n =: cur words cword prev _get_comp_words_by_ref -n =: cur words cword prev
_git __git_wrap__git_main
} }
" "
} }
@@ -71,7 +71,7 @@ __git_alias () {
alias_str="$1"; cmd_prefix="$2"; cmd="$3"; alias_str="$1"; cmd_prefix="$2"; cmd="$3";
if [ $# -gt 2 ]; then if [ $# -gt 2 ]; then
shift 3 2>/dev/null shift 3 2>/dev/null
cmd_args=$@ cmd_args=("$@")
fi fi
alias $alias_str="$cmd_prefix $cmd${cmd_args:+ }${cmd_args[*]}" alias $alias_str="$cmd_prefix $cmd${cmd_args:+ }${cmd_args[*]}"
@@ -89,6 +89,7 @@ _alias "$git_add_shortcuts_alias" 'git_add_shortcuts'
_alias "$exec_scmb_expand_args_alias" 'exec_scmb_expand_args' _alias "$exec_scmb_expand_args_alias" 'exec_scmb_expand_args'
_alias "$git_show_files_alias" 'git_show_affected_files' _alias "$git_show_files_alias" 'git_show_affected_files'
_alias "$git_commit_all_alias" 'git_commit_all' _alias "$git_commit_all_alias" 'git_commit_all'
_alias "$git_grep_shortcuts_alias" 'git_grep_shortcuts'
# Git Index alias # Git Index alias
_alias "$git_index_alias" 'git_index' _alias "$git_index_alias" 'git_index'
@@ -100,21 +101,23 @@ if [ "$git_setup_aliases" = "yes" ]; then
__git_alias "$git_checkout_alias" 'git' 'checkout' __git_alias "$git_checkout_alias" 'git' 'checkout'
__git_alias "$git_commit_alias" 'git' 'commit' __git_alias "$git_commit_alias" 'git' 'commit'
__git_alias "$git_commit_verbose_alias" 'git' 'commit' '--verbose' __git_alias "$git_commit_verbose_alias" 'git' 'commit' '--verbose'
__git_alias "$git_reset_alias" 'git' 'reset' '--' __git_alias "$git_reset_alias" 'git' 'reset'
__git_alias "$git_reset_hard_alias" 'git' 'reset' '--hard' __git_alias "$git_reset_hard_alias" 'git' 'reset' '--hard'
__git_alias "$git_rm_alias" 'git' 'rm' __git_alias "$git_rm_alias" 'git' 'rm'
__git_alias "$git_blame_alias" 'git' 'blame' __git_alias "$git_blame_alias" 'git' 'blame'
__git_alias "$git_diff_no_whitespace_alias" 'git' 'diff' '-w' '--' __git_alias "$git_diff_no_whitespace_alias" 'git' 'diff' '-w'
__git_alias "$git_diff_alias" 'git' 'diff' __git_alias "$git_diff_alias" 'git' 'diff'
__git_alias "$git_diff_file_alias" 'git' 'diff' '--' __git_alias "$git_diff_file_alias" 'git' 'diff'
__git_alias "$git_diff_word_alias" 'git' 'diff' '--word-diff' __git_alias "$git_diff_word_alias" 'git' 'diff' '--word-diff'
__git_alias "$git_diff_cached_alias" 'git' 'diff' '--cached --' __git_alias "$git_diff_cached_alias" 'git' 'diff' '--cached'
__git_alias "$git_add_patch_alias" 'git' 'add' '-p' __git_alias "$git_add_patch_alias" 'git' 'add' '-p'
__git_alias "$git_add_updated_alias" 'git' 'add' '-u' __git_alias "$git_add_updated_alias" 'git' 'add' '-u'
__git_alias "$git_difftool_alias" 'git' 'difftool' __git_alias "$git_difftool_alias" 'git' 'difftool'
__git_alias "$git_difftool_meld_alias" 'git' 'difftool -y -t meld' __git_alias "$git_difftool_meld_alias" 'git' 'difftool -y -t meld'
__git_alias "$git_difftool_vimdiff_alias" 'git' 'difftool -y -t vimdiff' __git_alias "$git_difftool_vimdiff_alias" 'git' 'difftool -y -t vimdiff'
__git_alias "$git_difftool_gvimdiff_alias" 'git' 'difftool -y -t gvimdiff' __git_alias "$git_difftool_gvimdiff_alias" 'git' 'difftool -y -t gvimdiff'
__git_alias "$git_mergetool_alias" 'git' 'mergetool'
__git_alias "$git_restore_alias" 'git' 'restore'
# Custom default format for git log # Custom default format for git log
git_log_command="log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit" git_log_command="log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
@@ -157,6 +160,7 @@ if [ "$git_setup_aliases" = "yes" ]; then
__git_alias "$git_submodule_update_rec_alias" 'git' 'submodule' 'update' '--init' '--recursive' __git_alias "$git_submodule_update_rec_alias" 'git' 'submodule' 'update' '--init' '--recursive'
__git_alias "$git_whatchanged_alias" 'git' 'whatchanged' __git_alias "$git_whatchanged_alias" 'git' 'whatchanged'
__git_alias "$git_apply_alias" 'git' 'apply' __git_alias "$git_apply_alias" 'git' 'apply'
__git_alias "$git_switch_alias" 'git' 'switch'
# Compound/complex commands # Compound/complex commands
_alias "$git_fetch_all_alias" 'git fetch --all' _alias "$git_fetch_all_alias" 'git fetch --all'
@@ -184,7 +188,7 @@ if [ $shell = "bash" ]; then
[[ -s "/usr/share/git/completion/git-completion.bash" ]] && source "/usr/share/git/completion/git-completion.bash" [[ -s "/usr/share/git/completion/git-completion.bash" ]] && source "/usr/share/git/completion/git-completion.bash"
# new path in Ubuntu 13.04 # new path in Ubuntu 13.04
[[ -s "/usr/share/bash-completion/completions/git" ]] && source "/usr/share/bash-completion/completions/git" [[ -s "/usr/share/bash-completion/completions/git" ]] && source "/usr/share/bash-completion/completions/git"
complete -o default -o nospace -F _git $git_alias complete -o default -o nospace -F __git_wrap__git_main $git_alias
# Git repo management & aliases. # Git repo management & aliases.
# If you know how to rewrite _git_index_tab_completion() for zsh, please send me a pull request! # If you know how to rewrite _git_index_tab_completion() for zsh, please send me a pull request!

View File

@@ -20,9 +20,9 @@ function _scmb_git_branch_shortcuts {
return 1 return 1
fi fi
# Use ruby to inject numbers into ls output # Use ruby to inject numbers into git branch output
ruby -e "$( cat <<EOF ruby -e "$( cat <<EOF
output = %x($_git_cmd branch --color=always $@) output = %x($_git_cmd branch --color=always $(token_quote "$@"))
line_count = output.lines.to_a.size line_count = output.lines.to_a.size
output.lines.each_with_index do |line, i| output.lines.each_with_index do |line, i|
spaces = (line_count > 9 && i < 9 ? " " : " ") spaces = (line_count > 9 && i < 9 ? " " : " ")
@@ -32,14 +32,12 @@ EOF
)" )"
# Set numbered file shortcut in variable # Set numbered file shortcut in variable
local e=1 local e=1 IFS=$'\n'
IFS=$'\n'
for branch in $($_git_cmd branch "$@" | sed "s/^[* ]\{2\}//"); do for branch in $($_git_cmd branch "$@" | sed "s/^[* ]\{2\}//"); do
export $git_env_char$e="$branch" export $git_env_char$e="$branch"
if [ "${scmbDebug:-}" = "true" ]; then echo "Set \$$git_env_char$e => $file"; fi if [ "${scmbDebug:-}" = "true" ]; then echo "Set \$$git_env_char$e => $file"; fi
let e++ let e++
done done
unset IFS
} }
__git_alias "$git_branch_alias" "_scmb_git_branch_shortcuts" "" __git_alias "$git_branch_alias" "_scmb_git_branch_shortcuts" ""

View File

@@ -16,7 +16,7 @@
# -------------------------------------------------------------------- # --------------------------------------------------------------------
git_status_shortcuts() { git_status_shortcuts() {
zsh_compat # Ensure shwordsplit is on for zsh zsh_compat # Ensure shwordsplit is on for zsh
IFS=$'\n' local IFS=$'\n'
local git_status="$(git status --porcelain 2> /dev/null)" local git_status="$(git status --porcelain 2> /dev/null)"
local i local i
@@ -95,7 +95,7 @@ git_status_shortcuts() {
fi fi
done done
IFS=" " local IFS=" "
grp_num=1 grp_num=1
for heading in 'Changes to be committed' 'Unmerged paths' 'Changes not staged for commit' 'Untracked files'; do for heading in 'Changes to be committed' 'Unmerged paths' 'Changes not staged for commit' 'Untracked files'; do
# If no group specified as param, or specified group is current group # If no group specified as param, or specified group is current group
@@ -114,11 +114,12 @@ git_status_shortcuts() {
# so just use plain 'git status' # so just use plain 'git status'
git status git status
fi fi
unset IFS
zsh_reset # Reset zsh environment to default zsh_reset # Reset zsh environment to default
} }
# Template function for 'git_status_shortcuts'. # Template function for 'git_status_shortcuts'.
_gs_output_file_group() { _gs_output_file_group() {
local relative
for i in ${stat_grp[$1]}; do for i in ${stat_grp[$1]}; do
# Print colored hashes & files based on modification groups # Print colored hashes & files based on modification groups
local c_group="\033[0;$(eval echo -e \$c_grp_$1)" local c_group="\033[0;$(eval echo -e \$c_grp_$1)"
@@ -127,9 +128,10 @@ _gs_output_file_group() {
if [ -z "$project_root" ]; then if [ -z "$project_root" ]; then
relative="${stat_file[$i]}" relative="${stat_file[$i]}"
else else
dest=$(readlink -f "$project_root/${stat_file[$i]}") local absolute="$project_root/${stat_file[$i]}"
local dest=$(readlink -f "$absolute")
local pwd=$(readlink -f "$PWD") local pwd=$(readlink -f "$PWD")
relative="$(_gs_relative_path "$pwd" "$dest" )" relative="$(_gs_relative_path "$pwd" "${dest:-$absolute}" )"
fi fi
if [[ $f -gt 10 && $e -lt 10 ]]; then local pad=" "; else local pad=""; fi # (padding) if [[ $f -gt 10 && $e -lt 10 ]]; then local pad=" "; else local pad=""; fi # (padding)
@@ -150,7 +152,7 @@ _gs_relative_path(){
# Credit to 'pini' for the following script. # Credit to 'pini' for the following script.
# (http://stackoverflow.com/questions/2564634/bash-convert-absolute-path-into-relative-path-given-a-current-directory) # (http://stackoverflow.com/questions/2564634/bash-convert-absolute-path-into-relative-path-given-a-current-directory)
target=$2; common_part=$1; back="" target=$2; common_part=$1; back=""
while [[ "${target#$common_part}" == "${target}" ]]; do while [[ -n "${common_part}" && "${target#$common_part}" == "${target}" ]]; do
common_part="${common_part%/*}" common_part="${common_part%/*}"
back="../${back}" back="../${back}"
done done

47
lib/git/grep_shortcuts.rb Normal file
View File

@@ -0,0 +1,47 @@
#!/usr/bin/env ruby
# encoding: UTF-8
PROJECT_ROOT = File.exist?(".git") ? Dir.pwd : `\git rev-parse --show-toplevel 2> /dev/null`.strip
COLORS = {
:rst => "\033[0m",
:del => "\033[0;31m",
:mod => "\033[0;32m",
:new => "\033[0;33m",
:ren => "\033[0;34m",
:cpy => "\033[0;33m",
:typ => "\033[0;35m",
:unt => "\033[0;36m",
:dark => "\033[2;37m",
:branch => "\033[1m",
:header => "\033[0m"
}
COLOR_MATCH = /\e\[[0-9;]*[mK]/
output_files = []
stdin = STDIN.set_encoding(Encoding::ASCII_8BIT)
while stdin.gets
if $. > 1000
puts "Only showing first 1000 results. Please refine your search."
break
end
print "#{COLORS[:dark]}[#{COLORS[:rst]}#{$.}#{COLORS[:dark]}]#{COLORS[:rst]} "
matches = $_.match(/(^.+?)#{COLOR_MATCH}?:#{COLOR_MATCH}?(\d+)?/)
file = matches[1]
line = matches[2]
output_files << "#{file}#{line ? ":#{line}" : ""}"
puts $_
end
print "@@filelist@@::"
output_files.each_with_index {|f,i|
# If file starts with a '~', treat it as a relative path.
# This is important when dealing with symlinks
print "|" unless i == 0
print f.start_with?("~") ? f.sub(/~/, '') : File.join(PROJECT_ROOT, f)
}
puts

24
lib/git/grep_shortcuts.sh Normal file
View File

@@ -0,0 +1,24 @@
git_grep_shortcuts() {
fail_if_not_git_repo || return 1
git_clear_vars
# Run ruby script, store output
tmp_grep_results="$(git rev-parse --git-dir)/tmp_grep_results_$$"
git grep -n --color=always "$@" |
/usr/bin/env ruby "$scmbDir/lib/git/grep_shortcuts.rb" >"$tmp_grep_results"
# Fetch list of files from last line of script output
files="$(tail -1 "$tmp_grep_results" | sed 's%@@filelist@@::%%g')"
# Export numbered env variables for each file
IFS="|"
local e=1
for file in ${=files}; do
export $git_env_char$e="$file"
let e++
done
IFS=$' \t\n'
# Print status
cat "$tmp_grep_results" | sed '$d' | less -SfRMXFi
rm -f "$tmp_grep_results"
}

View File

@@ -14,3 +14,10 @@ function fail_if_not_git_repo() {
fi fi
return 0 return 0
} }
bin_path() {
if [[ -n ${ZSH_VERSION:-} ]];
then builtin whence -cp "$1" 2> /dev/null
else builtin type -P "$1"
fi
}

View File

@@ -24,16 +24,24 @@ _bind(){
if [[ "$git_keyboard_shortcuts_enabled" = "true" ]]; then if [[ "$git_keyboard_shortcuts_enabled" = "true" ]]; then
case "$-" in case "$-" in
*i*) *i*)
if [ -n "$ZSH_VERSION" ]; then
RETURN_CHAR="^M"
else
RETURN_CHAR="\n"
fi
# Uses emacs style keybindings, so vi mode is not supported for now # Uses emacs style keybindings, so vi mode is not supported for now
if ! set -o | grep -q '^vi .*on$'; then if ! set -o | grep -q '^vi .*on$'; then
if [[ $shell == "zsh" ]]; then if [[ $shell == "zsh" ]]; then
_bind "$git_commit_all_keys" " git_commit_all""\n" _bind "$git_commit_all_keys" " git_commit_all""$RETURN_CHAR"
_bind "$git_add_and_commit_keys" " \033[1~ git_add_and_commit ""\n" _bind "$git_add_and_commit_keys" " \033[1~ git_add_and_commit ""$RETURN_CHAR"
_bind "$git_commit_all_with_ci_skip_keys" " \033[1~ APPEND='[ci skip]' git_commit_all ""\n" _bind "$git_commit_all_with_ci_skip_keys" " \033[1~ GIT_COMMIT_MSG_SUFFIX='[ci skip]' git_commit_all ""$RETURN_CHAR"
_bind "$git_add_and_amend_commit_keys" " git add --all . && git commit --amend -C HEAD""$RETURN_CHAR"
else else
_bind "$git_commit_all_keys" "\" git_commit_all\n\"" _bind "$git_commit_all_keys" "\" git_commit_all$RETURN_CHAR\""
_bind "$git_add_and_commit_keys" "\"\C-A git_add_and_commit \n\"" _bind "$git_add_and_commit_keys" "\"\C-A git_add_and_commit $RETURN_CHAR\""
_bind "$git_commit_all_with_ci_skip_keys" "\"\C-A APPEND='[ci skip]' git_commit_all \n\"" _bind "$git_commit_all_with_ci_skip_keys" "\"\C-A GIT_COMMIT_MSG_SUFFIX='[ci skip]' git_commit_all $RETURN_CHAR\""
_bind "$git_add_and_amend_commit_keys" "\" git add --all . && git commit --amend -C HEAD$RETURN_CHAR\""
fi fi
fi fi

View File

@@ -51,7 +51,7 @@
function git_index() { function git_index() {
IFS=$'\n' local IFS=$'\n'
if [ -z "$1" ]; then if [ -z "$1" ]; then
# Just change to $GIT_REPO_DIR if no params given. # Just change to $GIT_REPO_DIR if no params given.
"cd" $GIT_REPO_DIR "cd" $GIT_REPO_DIR
@@ -68,8 +68,8 @@ function git_index() {
elif [ "$1" = "--list" ] || [ "$1" = "-l" ]; then elif [ "$1" = "--list" ] || [ "$1" = "-l" ]; then
echo -e "$_bld_col$(_git_index_count)$_txt_col Git repositories in $_bld_col$GIT_REPO_DIR$_txt_col:\n" echo -e "$_bld_col$(_git_index_count)$_txt_col Git repositories in $_bld_col$GIT_REPO_DIR$_txt_col:\n"
for repo in $(_git_index_dirs_without_home); do for repo in $(_git_index_dirs_without_home); do
echo $(basename $repo) : $repo echo $(basename $repo | sed "s/ /_/g") : $repo
done | sort | column -t -s ':' done | sort -t ":" -k1,1 | column -t -s ':'
elif [ "$1" = "--count-by-host" ]; then elif [ "$1" = "--count-by-host" ]; then
echo -e "=== Producing a report of the number of repos per host...\n" echo -e "=== Producing a report of the number of repos per host...\n"
_git_index_batch_cmd git remote -v | \grep "origin.*(fetch)" | _git_index_batch_cmd git remote -v | \grep "origin.*(fetch)" |
@@ -103,7 +103,7 @@ function git_index() {
# -------------------- # --------------------
# Go to our base path # Go to our base path
if [ -n "$base_path" ]; then if [ -n "$base_path" ]; then
IFS=$' \t\n' local IFS=$' \t\n'
# evaluate ~ if necessary # evaluate ~ if necessary
if [[ "$base_path" == "~"* ]]; then if [[ "$base_path" == "~"* ]]; then
base_path=$(eval echo ${base_path%%/*})/${base_path#*/} base_path=$(eval echo ${base_path%%/*})/${base_path#*/}
@@ -116,7 +116,6 @@ function git_index() {
fi fi
fi fi
fi fi
unset IFS
} }
_git_index_dirs_without_home() { _git_index_dirs_without_home() {
@@ -126,12 +125,11 @@ _git_index_dirs_without_home() {
# Recursively searches for git repos in $GIT_REPO_DIR # Recursively searches for git repos in $GIT_REPO_DIR
function _find_git_repos() { function _find_git_repos() {
# Find all unarchived projects # Find all unarchived projects
IFS=$'\n' local IFS=$'\n'
for repo in $(find -L "$GIT_REPO_DIR" -maxdepth 5 -name ".git" -type d \! -wholename '*/archive/*'); do for repo in $(find -L "$GIT_REPO_DIR" -maxdepth 3 -name ".git" -type d \! -wholename '*/archive/*'); do
echo ${repo%/.git} # Return project folder, with trailing ':' echo ${repo%/.git} # Return project folder, with trailing ':'
_find_git_submodules $repo # Detect any submodules _find_git_submodules $repo # Detect any submodules
done done
unset IFS
} }
# List all submodules for a git repo, if any. # List all submodules for a git repo, if any.
@@ -146,11 +144,10 @@ function _find_git_submodules() {
function _rebuild_git_index() { function _rebuild_git_index() {
if [ "$1" != "--silent" ]; then echo -e "== Scanning $GIT_REPO_DIR for git repos & submodules..."; fi if [ "$1" != "--silent" ]; then echo -e "== Scanning $GIT_REPO_DIR for git repos & submodules..."; fi
# Get repos from src dir and custom dirs, then sort by basename # Get repos from src dir and custom dirs, then sort by basename
IFS=$'\n' local IFS=$'\n'
for repo in $(echo -e "$(_find_git_repos)\n$(echo $GIT_REPOS | sed "s/:/\\\\n/g")"); do for repo in $(echo -e "$(_find_git_repos)\n$(echo $GIT_REPOS | sed "s/:/\\\\n/g")"); do
echo $(basename $repo | sed "s/ /_/g") $repo echo $(basename $repo | sed "s/ /_/g"):$repo
done | sort | cut -d " " -f2- >| "$GIT_REPO_DIR/.git_index" done | sort -t ":" -k1,1 | cut -d ":" -f2- >| "$GIT_REPO_DIR/.git_index"
unset IFS
if [ "$1" != "--silent" ]; then if [ "$1" != "--silent" ]; then
echo -e "===== Indexed $_bld_col$(_git_index_count)$_txt_col repos in $GIT_REPO_DIR/.git_index" echo -e "===== Indexed $_bld_col$(_git_index_count)$_txt_col repos in $GIT_REPO_DIR/.git_index"
@@ -205,39 +202,39 @@ _git_index_update_all_branches() {
return return
fi fi
local remotes merges branches # zsh 5.0.2 requires local separate to assignment for arrays
local remote merge remotes merges branches
# Get branch configuration from .git/config # Get branch configuration from .git/config
IFS=$'\n' local IFS=$'\n'
for branch in $($GIT_BINARY branch 2> /dev/null | sed -e 's/.\{2\}\(.*\)/\1/'); do for branch in $($GIT_BINARY branch 2> /dev/null | sed -e 's/.\{2\}\(.*\)/\1/'); do
# Skip '(no branch)' # Skip '(no branch)'
if [[ "$branch" = "(no branch)" ]]; then continue; fi if [[ "$branch" = "(no branch)" ]]; then continue; fi
local remote=$(git config --get branch.$branch.remote) remote=$(git config --get "branch.$branch.remote")
local merge=$(git config --get branch.$branch.merge) merge=$(git config --get "branch.$branch.merge")
# Ignore branch if remote and merge is not configured # Ignore branch if remote and merge is not configured
if [[ -n "$remote" ]] && [[ -n "$merge" ]]; then if [[ -n "$remote" ]] && [[ -n "$merge" ]]; then
branches=(${branches[@]} "$branch") branches=("${branches[@]}" "$branch")
remotes=(${remotes[@]} "$remote") remotes=("${remotes[@]}" "$remote")
# Get branch from merge ref (refs/heads/master => master) # Get branch from merge ref (refs/heads/master => master)
merges=(${merges[@]} "$(basename $merge)") merges=("${merges[@]}" "$(basename "$merge")")
else else
echo "=== Skipping $branch: remote and merge refs are not configured." echo "=== Skipping $branch: remote and merge refs are not configured."
fi fi
done done
unset IFS
# Update all remotes if there are any branches to update # Update all remotes if there are any branches to update
if [ -n "${branches[*]}" ]; then git fetch --all 2> /dev/null; fi if [ -n "${branches[*]}" ]; then git fetch --all 2> /dev/null; fi
local index=0 local index=0
# Iterate over branches, and update those that can be fast-forwarded # Iterate over branches, and update those that can be fast-forwarded
for branch in ${branches[@]}; do for branch in "${branches[@]}"; do
branch_rev="$(git rev-parse $branch)" branch_rev="$(git rev-parse $branch)"
# Local branch can be fast-forwarded if revision is ancestor of remote revision, and not the same. # Local branch can be fast-forwarded if revision is ancestor of remote revision, and not the same.
# (see http://stackoverflow.com/a/2934062/304706) # (see http://stackoverflow.com/a/2934062/304706)
if [[ "$branch_rev" != "$(git rev-parse ${remotes[$index]}/${merges[$index]})" ]] && \ if [[ "$branch_rev" != "$(git rev-parse "${remotes[$index]}/${merges[$index]}")" ]] && \
[[ "$(git merge-base $branch_rev ${remotes[$index]}/${merges[$index]})" = "$branch_rev" ]]; then [[ "$(git merge-base "$branch_rev" "${remotes[$index]}/${merges[$index]}")" = "$branch_rev" ]]; then
echo "=== Updating $branch branch in $base_path from ${remotes[$index]}/${merges[$index]}..." echo "=== Updating $branch branch in $base_path from ${remotes[$index]}/${merges[$index]}..."
# Checkout branch if we aren't already on it. # Checkout branch if we aren't already on it.
if [[ "$branch" != "$(parse_git_branch)" ]]; then git checkout $branch; fi if [[ "$branch" != "$(parse_git_branch)" ]]; then git checkout $branch; fi
@@ -268,11 +265,11 @@ function _git_index_batch_cmd() {
cwd="$PWD" cwd="$PWD"
if [ -n "$1" ]; then if [ -n "$1" ]; then
echo -e "== Running command for $_bld_col$(_git_index_count)$_txt_col repos...\n" echo -e "== Running command for $_bld_col$(_git_index_count)$_txt_col repos...\n"
unset IFS local IFS=$'\n'
local base_path local base_path
for base_path in $(sed -e "s/--.*//" "$GIT_REPO_DIR/.git_index" | \grep . | sort); do for base_path in $(sed -e "s/--.*//" "$GIT_REPO_DIR/.git_index" | \grep . | sort); do
builtin cd "$base_path" builtin cd "$base_path"
$@ "$@"
done done
else else
echo "Please give a command to run for all repos. (It may be useful to write your command as a function or script.)" echo "Please give a command to run for all repos. (It may be useful to write your command as a function or script.)"
@@ -285,8 +282,7 @@ if [ $shell = 'bash' ]; then
# Bash tab completion function for git_index() # Bash tab completion function for git_index()
function _git_index_tab_completion() { function _git_index_tab_completion() {
_check_git_index _check_git_index
local curw local curw IFS=$'\n'
IFS=$'\n'
COMPREPLY=() COMPREPLY=()
curw=${COMP_WORDS[COMP_CWORD]} curw=${COMP_WORDS[COMP_CWORD]}
@@ -313,10 +309,9 @@ if [ $shell = 'bash' ]; then
else else
COMPREPLY=($(compgen -W '$(sed -e "s:.*/::" -e "s:$:/:" "$GIT_REPO_DIR/.git_index" | sort)' -- $curw)) COMPREPLY=($(compgen -W '$(sed -e "s:.*/::" -e "s:$:/:" "$GIT_REPO_DIR/.git_index" | sort)' -- $curw))
fi fi
unset IFS
return 0 return 0
} }
else else # Zsh tab completion function for git_index()
function _git_index_tab_completion() { function _git_index_tab_completion() {
typeset -A opt_args typeset -A opt_args
local state state_descr context line local state state_descr context line

View File

@@ -5,9 +5,9 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
if test | sed -E 's///g' 2>/dev/null; then if sed -E 's///g' </dev/null &>/dev/null; then
SED_REGEX_ARG="E" SED_REGEX_ARG="E"
elif test | sed -r 's///g' 2>/dev/null; then elif sed -r 's///g' </dev/null &>/dev/null; then
SED_REGEX_ARG="r" SED_REGEX_ARG="r"
else else
echo "Cannot determine extended regex argument for sed! (Doesn't respond to either -E or -r)" echo "Cannot determine extended regex argument for sed! (Doesn't respond to either -E or -r)"
@@ -23,19 +23,19 @@ if [ "$shell_command_wrapping_enabled" = "true" ] || [ "$bash_command_wrapping_e
# Define 'whence' for bash, to get the value of an alias # Define 'whence' for bash, to get the value of an alias
type whence > /dev/null 2>&1 || function whence() { LC_MESSAGES="C" type "$@" | sed -$SED_REGEX_ARG -e "s/.*is aliased to \`//" -e "s/'$//"; } type whence > /dev/null 2>&1 || function whence() { LC_MESSAGES="C" type "$@" | sed -$SED_REGEX_ARG -e "s/.*is aliased to \`//" -e "s/'$//"; }
local cmd='' local cmd=''
for cmd in $(echo $scmb_wrapped_shell_commands); do for cmd in $scmb_wrapped_shell_commands; do
if [ "${scmbDebug:-}" = "true" ]; then echo "SCMB: Wrapping $cmd..."; fi if [ "${scmbDebug:-}" = "true" ]; then echo "SCMB: Wrapping $cmd..."; fi
# Special check for 'cd', to make sure SCM Breeze is loaded after RVM # Special check for 'cd', to make sure SCM Breeze is loaded after RVM
if [ "$cmd" = 'cd' ]; then if [ "$cmd" = 'cd' ]; then
if [ -e "$HOME/.rvm" ] && ! type rvm > /dev/null 2>&1; then if [ -e "$HOME/.rvm" ] && ! type rvm > /dev/null 2>&1; then
echo -e "\033[0;31mSCM Breeze must be loaded \033[1;31mafter\033[0;31m RVM, otherwise there will be a conflict when RVM wraps the 'cd' command.\033[0m" echo -e "\\033[0;31mSCM Breeze must be loaded \\033[1;31mafter\\033[0;31m RVM, otherwise there will be a conflict when RVM wraps the 'cd' command.\\033[0m"
echo -e "\033[0;31mPlease move the line that loads SCM Breeze to the bottom of your ~/.bashrc\033[0m" echo -e "\\033[0;31mPlease move the line that loads SCM Breeze to the bottom of your ~/.bashrc\\033[0m"
continue continue
fi fi
fi fi
case "$(LC_MESSAGES="C" type $cmd 2>&1)" in case "$(LC_MESSAGES="C" type "$cmd" 2>&1)" in
# Don't do anything if command already aliased, or not found. # Don't do anything if command already aliased, or not found.
*'exec_scmb_expand_args'*) *'exec_scmb_expand_args'*)
@@ -49,10 +49,10 @@ if [ "$shell_command_wrapping_enabled" = "true" ] || [ "$bash_command_wrapping_e
# Store original alias # Store original alias
local original_alias="$(whence $cmd)" local original_alias="$(whence $cmd)"
# Remove alias, so that we can find binary # Remove alias, so that we can find binary
unalias $cmd unalias "$cmd"
# Detect original $cmd type, and escape # Detect original $cmd type, and escape
case "$(LC_MESSAGES="C" type $cmd 2>&1)" in case "$(LC_MESSAGES="C" type "$cmd" 2>&1)" in
# Escape shell builtins with 'builtin' # Escape shell builtins with 'builtin'
*'is a shell builtin'*) local escaped_cmd="builtin $cmd";; *'is a shell builtin'*) local escaped_cmd="builtin $cmd";;
# Get full path for files with 'find_binary' function # Get full path for files with 'find_binary' function
@@ -67,9 +67,9 @@ if [ "$shell_command_wrapping_enabled" = "true" ] || [ "$bash_command_wrapping_e
*'is a'*'function'*) *'is a'*'function'*)
if [ "${scmbDebug:-}" = "true" ]; then echo "SCMB: $cmd is a function"; fi if [ "${scmbDebug:-}" = "true" ]; then echo "SCMB: $cmd is a function"; fi
# Copy old function into new name # Copy old function into new name
eval "$(declare -f $cmd | sed -$SED_REGEX_ARG "s/^$cmd \(\)/__original_$cmd ()/")" eval "$(declare -f "$cmd" | sed -"$SED_REGEX_ARG" "s/^$cmd \\(\\)/__original_$cmd ()/")"
# Remove function # Remove function
unset -f $cmd unset -f "$cmd"
# Create function that wraps old function # Create function that wraps old function
eval "${cmd}(){ exec_scmb_expand_args __original_${cmd} \"\$@\"; }";; eval "${cmd}(){ exec_scmb_expand_args __original_${cmd} \"\$@\"; }";;
@@ -92,61 +92,95 @@ if [ "$shell_command_wrapping_enabled" = "true" ] || [ "$bash_command_wrapping_e
fi fi
# BSD ls is different to Linux (GNU) ls
# Test for BSD ls
if ! ls --color=auto > /dev/null 2>&1; then
# ls is BSD
_ls_bsd="BSD"
fi
# Test if readlink supports -f option, otherwise use perl (a bit slower)
if ! readlink -f > /dev/null 2>&1; then
_abs_path_command='perl -e "use Cwd "abs_path"; print abs_path(shift)"'
else
_abs_path_command="readlink -f"
fi
# Function wrapper around 'll' # Function wrapper around 'll'
# Adds numbered shortcuts to output of ls -l, just like 'git status' # Adds numbered shortcuts to output of ls -l, just like 'git status'
if [ "$shell_ls_aliases_enabled" = "true" ] && which ruby > /dev/null 2>&1; then if [ "$shell_ls_aliases_enabled" = "true" ] && builtin command -v ruby > /dev/null 2>&1; then
# BSD ls is different to Linux (GNU) ls
# Test for BSD ls
if ! ls --color=auto > /dev/null 2>&1; then
# ls is BSD
_ls_bsd="BSD"
fi
# Test if readlink supports -f option, test for greadlink on Mac, then fallback to perl
if \readlink -f / > /dev/null 2>&1; then
_abs_path_command=(readlink -f)
elif greadlink -f / > /dev/null 2>&1; then
_abs_path_command=(greadlink -f)
else
_abs_path_command=(perl -e 'use Cwd abs_path; print abs_path(shift)')
fi
unalias ll > /dev/null 2>&1; unset -f ll > /dev/null 2>&1 unalias ll > /dev/null 2>&1; unset -f ll > /dev/null 2>&1
function ls_with_file_shortcuts { function ls_with_file_shortcuts {
local ll_output local ll_output
local ll_command # Ensure sort ordering of the two invocations is the same
if [ "$_ls_bsd" != "BSD" ]; then if [ "$_ls_bsd" != "BSD" ]; then
ll_output="$(\ls -lhv --group-directories-first --color "$@")" ll_command=(\ls -hv --group-directories-first)
ll_output="$("${ll_command[@]}" -l --color "$@")"
else else
ll_output="$(CLICOLOR_FORCE=1 \ls -l -G "$@")" ll_command=(\ls)
ll_output="$(CLICOLOR_FORCE=1 "${ll_command[@]}" -lG "$@")"
fi fi
if [[ $shell == "zsh" ]]; then if [[ $shell == "zsh" ]]; then
# Ensure sh_word_split is on # Ensure sh_word_split is on
if setopt | grep -q shwordsplit; then SHWORDSPLIT_ON=true; fi [[ -o shwordsplit ]] && SHWORDSPLIT_ON=true
setopt shwordsplit setopt shwordsplit
fi fi
# Parse path from args # Get the directory that `ls` is being run relative to.
IFS=$'\n' # Only allow one directory to avoid incorrect $e# variables when listing
for arg in $@; do # multiple directories (issue #274)
if [ -d "$arg" ]; then local rel_path="${arg%/}"; fi local IFS=$'\n'
local rel_path
for arg in "$@"; do
if [[ -e $arg ]]; then # Path rather than option to ls
if [[ -z $rel_path ]]; then # We are seeing our first pathname
if [[ -d $arg ]]; then # It's a directory
rel_path=$arg
else # It's a file, expand the current directory
rel_path=.
fi
elif [[ -d $arg || ( -f $arg && $rel_path != . ) ]]; then
if [[ -f $arg ]]; then arg=$PWD; fi # Get directory for current argument
# We've already seen a different directory. Quit to avoid damage (issue #274)
printf 'scm_breeze: Cannot list relative to both directories:\n %s\n %s\n' "$arg" "$rel_path" >&2
printf 'Currently only listing a single directory is supported. See issue #274.\n' >&2
return 1
fi
fi
done done
unset IFS rel_path=$("${_abs_path_command[@]}" ${rel_path:-$PWD})
# Replace user/group with user symbol, if defined at ~/.user_sym # Replace user/group with user symbol, if defined at ~/.user_sym
# Before : -rw-rw-r-- 1 ndbroadbent ndbroadbent 1.1K Sep 19 21:39 scm_breeze.sh # Before : -rw-rw-r-- 1 ndbroadbent ndbroadbent 1.1K Sep 19 21:39 scm_breeze.sh
# After : -rw-rw-r-- 1 𝐍 𝐍 1.1K Sep 19 21:39 scm_breeze.sh # After : -rw-rw-r-- 1 𝐍 𝐍 1.1K Sep 19 21:39 scm_breeze.sh
if [ -e $HOME/.user_sym ]; then if [ -e "$HOME"/.user_sym ]; then
# Little bit of ruby golf to rejustify the user/group/size columns after replacement # Little bit of ruby golf to rejustify the user/group/size columns after replacement
# TODO(ghthor): Convert this to a cat <<EOF to improve readibility
function rejustify_ls_columns(){ function rejustify_ls_columns(){
ruby -e "o=STDIN.read;re=/^(([^ ]* +){2})(([^ ]* +){3})/;\ ruby -e "o=STDIN.read;re=/^(([^ ]* +){2})(([^ ]* +){3})/;\
u,g,s=o.lines.map{|l|l[re,3]}.compact.map(&:split).transpose.map{|a|a.map(&:size).max+1};\ u,g,s=o.lines.map{|l|l[re,3]}.compact.map(&:split).transpose.map{|a|a.map(&:size).max+1};\
puts o.lines.map{|l|l.sub(re){|m|\"%s%-#{u}s %-#{g}s%#{s}s \"%[\$1,*\$3.split]}}" puts o.lines.map{|l|l.sub(re){|m|\"%s%-#{u}s %-#{g}s%#{s}s \"%[\$1,*\$3.split]}}"
} }
ll_output=$(echo "$ll_output" | \sed -$SED_REGEX_ARG "s/ $USER/ $(/bin/cat $HOME/.user_sym)/g" | rejustify_ls_columns) local USER_SYM=$(/bin/cat $HOME/.user_sym)
if [ -f "$HOME/.staff_sym" ]; then
local STAFF_SYM=$(/bin/cat $HOME/.staff_sym)
ll_output=$(echo "$ll_output" | \
\sed -$SED_REGEX_ARG "s/ $USER staff/ $USER_SYM $STAFF_SYM /g" | \
rejustify_ls_columns)
else
ll_output=$(echo "$ll_output" | \
\sed -$SED_REGEX_ARG "s/ $USER/ $USER_SYM /g" | \
rejustify_ls_columns)
fi
fi fi
# Bail if there are two many lines to process
if [ "$(echo "$ll_output" | wc -l)" -gt "50" ]; then if [ "$(echo "$ll_output" | wc -l)" -gt "50" ]; then
echo -e "\033[33mToo many files to create shortcuts. Running plain ll command...\033[0m" echo -e '\033[33mToo many files to create shortcuts. Running plain ll command...\033[0m' >&2
echo "$ll_output" echo "$ll_output"
return 1 return 1
fi fi
@@ -169,23 +203,26 @@ EOF
local ll_files='' local ll_files=''
local file='' local file=''
# XXX FIXME XXX
# There is a race condition here: If a file is removed between the above
# and this second call of `ls` then the $e# variables can refer to the
# wrong files.
if [ -z $_ls_bsd ]; then if [ -z $_ls_bsd ]; then
ll_files="$(\ls -v --group-directories-first --color=never "$@")" ll_files="$(QUOTING_STYLE=literal "${ll_command[@]}" --color=never "$@")"
else else
ll_files="$(\ls "$@")" ll_files="$("${ll_command[@]}" "$@")"
fi fi
IFS=$'\n' local IFS=$'\n'
for file in $ll_files; do for file in $ll_files; do
if [ -n "$rel_path" ]; then file="$rel_path/$file"; fi file=$rel_path/$file
export $git_env_char$e="$(eval $_abs_path_command \"${file//\"/\\\"}\")" export $git_env_char$e=$("${_abs_path_command[@]}" "$file")
if [ "${scmbDebug:-}" = "true" ]; then echo "Set \$$git_env_char$e => $file"; fi if [[ ${scmbDebug:-} = true ]]; then echo "Set \$$git_env_char$e => $file"; fi
let e++ let e++
done done
unset IFS
# Turn off shwordsplit unless it was on previously # Turn off shwordsplit unless it was on previously
if [[ $shell == "zsh" ]] && [ -z "$SHWORDSPLIT_ON" ]; then unsetopt shwordsplit; fi if [[ $shell == "zsh" && -z $SHWORDSPLIT_ON ]]; then unsetopt shwordsplit; fi
} }
# Setup aliases # Setup aliases

View File

@@ -26,7 +26,7 @@
git_status_lines = @git_status.split("\n") git_status_lines = @git_status.split("\n")
git_branch = git_status_lines[0] git_branch = git_status_lines[0]
@branch = git_branch[/^## (?:Initial commit on )?([^ \.]+)/, 1] @branch = git_branch[/^## (?:Initial commit on )?([^ ]+)/, 1]
@ahead = git_branch[/\[ahead ?(\d+).*\]/, 1] @ahead = git_branch[/\[ahead ?(\d+).*\]/, 1]
@behind = git_branch[/\[.*behind ?(\d+)\]/, 1] @behind = git_branch[/\[.*behind ?(\d+)\]/, 1]
@@ -76,16 +76,15 @@ difference = difference.length > 0 ? " #{@c[:dark]}| #{@c[:new]}#{difference}#
# If no changes, just display green no changes message and exit here # If no changes, just display green no changes message and exit here
if @git_status == "" if @changes.size == 0
puts "%s#%s On branch: %s#{@branch}#{difference} %s| \033[0;32mNo changes (working directory clean)%s" % [ puts "%s#%s On branch: %s#{@branch}#{difference}%s %s| \033[0;32mNo changes (working directory clean)%s" % [
@c[:dark], @c[:rst], @c[:branch], @c[:dark], @c[:rst] @c[:dark], @c[:rst], @c[:branch], @c[:rst], @c[:dark], @c[:rst]
] ]
exit exit
end end
puts "%s#%s On branch: %s#{@branch}#{difference}%s %s| [%s*%s]%s => $#{ENV["git_env_char"]}*\n%s#%s" % [
puts "%s#%s On branch: %s#{@branch}#{difference} %s| [%s*%s]%s => $#{ENV["git_env_char"]}*\n%s#%s" % [ @c[:dark], @c[:rst], @c[:branch], @c[:rst], @c[:dark], @c[:rst], @c[:dark], @c[:rst], @c[:dark], @c[:rst]
@c[:dark], @c[:rst], @c[:branch], @c[:dark], @c[:rst], @c[:dark], @c[:rst], @c[:dark], @c[:rst]
] ]
def has_modules? def has_modules?

View File

@@ -21,7 +21,7 @@ git_status_shortcuts() {
zsh_compat # Ensure shwordsplit is on for zsh zsh_compat # Ensure shwordsplit is on for zsh
git_clear_vars git_clear_vars
# Run ruby script, store output # Run ruby script, store output
local cmd_output="$(/usr/bin/env ruby "$scmbDir/lib/git/status_shortcuts.rb" $@)" local cmd_output="$(/usr/bin/env ruby "$scmbDir/lib/git/status_shortcuts.rb" "$@")"
# Print debug information if $scmbDebug = "true" # Print debug information if $scmbDebug = "true"
if [ "${scmbDebug:-}" = "true" ]; then if [ "${scmbDebug:-}" = "true" ]; then
printf "status_shortcuts.rb output => \n$cmd_output\n------------------------\n" printf "status_shortcuts.rb output => \n$cmd_output\n------------------------\n"
@@ -36,14 +36,13 @@ git_status_shortcuts() {
files="$(echo "$cmd_output" | \grep '@@filelist@@::' | sed 's%@@filelist@@::%%g')" files="$(echo "$cmd_output" | \grep '@@filelist@@::' | sed 's%@@filelist@@::%%g')"
if [ "${scmbDebug:-}" = "true" ]; then echo "filelist => $files"; fi if [ "${scmbDebug:-}" = "true" ]; then echo "filelist => $files"; fi
# Export numbered env variables for each file # Export numbered env variables for each file
IFS="|" local IFS="|"
local e=1 local e=1
for file in $files; do for file in $files; do
export $git_env_char$e="$file" export $git_env_char$e="$file"
if [ "${scmbDebug:-}" = "true" ]; then echo "Set \$$git_env_char$e => $file"; fi if [ "${scmbDebug:-}" = "true" ]; then echo "Set \$$git_env_char$e => $file"; fi
let e++ let e++
done done
unset IFS
if [ "${scmbDebug:-}" = "true" ]; then echo "------------------------"; fi if [ "${scmbDebug:-}" = "true" ]; then echo "------------------------"; fi
# Print status # Print status
@@ -80,10 +79,11 @@ git_add_shortcuts() {
git_silent_add_shortcuts() { git_silent_add_shortcuts() {
if [ -n "$1" ]; then if [ -n "$1" ]; then
# Expand args and process resulting set of files. # Expand args and process resulting set of files.
IFS=$'\t' local args
for file in $(scmb_expand_args "$@"); do eval args="$(scmb_expand_args "$@")" # populate $args array
for file in "${args[@]}"; do
# Use 'git rm' if file doesn't exist and 'ga_auto_remove' is enabled. # Use 'git rm' if file doesn't exist and 'ga_auto_remove' is enabled.
if [[ $ga_auto_remove == "yes" ]] && ! [ -e "$file" ]; then if [[ $ga_auto_remove = yes && ! -e $file ]]; then
echo -n "# " echo -n "# "
git rm "$file" git rm "$file"
else else
@@ -91,7 +91,6 @@ git_silent_add_shortcuts() {
echo -e "# Added '$file'" echo -e "# Added '$file'"
fi fi
done done
unset IFS
echo "#" echo "#"
fi fi
} }
@@ -100,18 +99,18 @@ git_silent_add_shortcuts() {
# and exports numbered environment variables for each file. # and exports numbered environment variables for each file.
git_show_affected_files(){ git_show_affected_files(){
fail_if_not_git_repo || return 1 fail_if_not_git_repo || return 1
f=0 # File count local f=0 # File count
# Show colored revision and commit message # Show colored revision and commit message
echo -n "# "; git show --oneline --name-only $@ | head -n1; echo "# " echo -n "# "; git show --oneline --name-only "$@" | head -n1; echo "# "
for file in $(git show --pretty="format:" --name-only $@ | \grep -v '^$'); do for file in $(git show --pretty="format:" --name-only "$@" | \grep -v '^$'); do
let f++ let f++
export $git_env_char$f=$file # Export numbered variable. export $git_env_char$f=$file # Export numbered variable.
echo -e "# \033[2;37m[\033[0m$f\033[2;37m]\033[0m $file" echo -e "# \033[2;37m[\033[0m$f\033[2;37m]\033[0m $file"
done; echo "# " done; echo "# "
} }
# Allows expansion of numbered shortcuts, ranges of shortcuts, or standard paths. # Allows expansion of numbered shortcuts, ranges of shortcuts, or standard paths.
# Return a string which can be `eval`ed like: eval args="$(scmb_expand_args "$@")"
# Numbered shortcut variables are produced by various commands, such as: # Numbered shortcut variables are produced by various commands, such as:
# * git_status_shortcuts() - git status implementation # * git_status_shortcuts() - git status implementation
# * git_show_affected_files() - shows files affected by a given SHA1, etc. # * git_show_affected_files() - shows files affected by a given SHA1, etc.
@@ -122,43 +121,52 @@ scmb_expand_args() {
shift shift
fi fi
first=1 local args
OLDIFS="$IFS"; IFS=" " # We need to split on spaces to loop over expanded range args=() # initially empty array. zsh 5.0.2 from Ubuntu 14.04 requires this to be separated
for arg in "$@"; do for arg in "$@"; do
if [[ "$arg" =~ ^[0-9]{0,4}$ ]] ; then # Substitute $e{*} variables for any integers if [[ "$arg" =~ ^[0-9]{0,4}$ ]] ; then # Substitute $e{*} variables for any integers
if [ "$first" -eq 1 ]; then first=0; else printf '\t'; fi
if [ -e "$arg" ]; then if [ -e "$arg" ]; then
# Don't expand files or directories with numeric names # Don't expand files or directories with numeric names
printf '%s' "$arg" args+=("$arg")
else else
_print_path "$relative" "$git_env_char$arg" args+=("$(_print_path "$relative" "$git_env_char$arg")")
fi fi
elif [[ "$arg" =~ ^[0-9]+-[0-9]+$ ]]; then # Expand ranges into $e{*} variables elif [[ "$arg" =~ ^[0-9]+-[0-9]+$ ]]; then # Expand ranges into $e{*} variables
for i in $(eval echo {${arg/-/..}}); do for i in $(eval echo {${arg/-/..}}); do
if [ "$first" -eq 1 ]; then first=0; else printf '\t'; fi args+=("$(_print_path "$relative" "$git_env_char$i")")
_print_path "$relative" "$git_env_char$i"
done done
else # Otherwise, treat $arg as a normal string. else # Otherwise, treat $arg as a normal string.
if [ "$first" -eq 1 ]; then first=0; else printf '\t'; fi args+=("$arg")
printf '%s' "$arg"
fi fi
done done
IFS="$OLDIFS"
# "declare -p" with zsh 5.0.2 on Ubuntu 14.04 creates a string that it cannot process:
# typeset -a args args=(one three six)
# There should be a ; between the two "args" tokens
# "declare -p" with bash 4.3.11(1) on Ubuntu 14.04 creates a string like:
# declare -a a='([0]="a" [1]="b c" [2]="d")'
# The RHS of this string is incompatible with zsh 5.0.2 and "eval args="
# Generate a quoted array string to assign to "eval args="
echo "( $(token_quote "${args[@]}") )"
} }
# Expand a variable (named by $2) into a (possibly relative) pathname
_print_path() { _print_path() {
if [ "$1" = 1 ]; then local pathname
eval printf '%s' "\"\$$2\"" | sed -e "s%$(pwd)/%%" | awk '{printf("%s", $0)}' pathname=$(eval printf '%s' "\"\${$2}\"")
else if [ "$1" = 1 ]; then # print relative
eval printf '%s' "\"\$$2\"" pathname=${pathname#$PWD/} # Remove $PWD from beginning of the path
fi fi
printf '%s' "$pathname"
} }
# Execute a command with expanded args, e.g. Delete files 6 to 12: $ ge rm 6-12 # Execute a command with expanded args, e.g. Delete files 6 to 12: $ ge rm 6-12
# Fails if command is a number or range (probably not worth fixing) # Fails if command is a number or range (probably not worth fixing)
exec_scmb_expand_args() { exec_scmb_expand_args() {
eval "$(scmb_expand_args "$@" | sed -e "s/\([][|;()<>^ \"'&]\)/"'\\\1/g')" local args
eval "args=$(scmb_expand_args "$@")" # populate $args array
_safe_eval "${args[@]}"
} }
# Clear numbered env variables # Clear numbered env variables
@@ -180,13 +188,13 @@ git_clear_vars() {
_git_resolve_merge_conflict() { _git_resolve_merge_conflict() {
if [ -n "$2" ]; then if [ -n "$2" ]; then
# Expand args and process resulting set of files. # Expand args and process resulting set of files.
IFS=$'\t' local args
for file in $(scmb_expand_args "${@:2}"); do eval "args=$(scmb_expand_args "$@")" # populate $args array
for file in "${args[@]:2}"; do
git checkout "--$1""s" "$file" # "--$1""s" is expanded to --ours or --theirs git checkout "--$1""s" "$file" # "--$1""s" is expanded to --ours or --theirs
git add "$file" git add "$file"
echo -e "# Added $1 version of '$file'" echo -e "# Added $1 version of '$file'"
done done
unset IFS
echo -e "# -- If you have finished resolving conflicts, commit the resolutions with 'git commit'" echo -e "# -- If you have finished resolving conflicts, commit the resolutions with 'git commit'"
fi fi
} }
@@ -203,29 +211,62 @@ theirs(){ _git_resolve_merge_conflict "their" "$@"; }
# * Add escaped commit command and unescaped message to bash history. # * Add escaped commit command and unescaped message to bash history.
git_commit_prompt() { git_commit_prompt() {
local commit_msg local commit_msg
local saved_commit_msg
if [ -f "/tmp/.git_commit_message~" ]; then
saved_commit_msg="$(cat /tmp/.git_commit_message~)"
echo -e "\033[0;36mLeave blank to use saved commit message: \033[0m$saved_commit_msg"
fi
if [[ $shell == "zsh" ]]; then if [[ $shell == "zsh" ]]; then
vared -h -p "Commit Message: " commit_msg vared -h -p "Commit Message: " commit_msg
else else
read -r -e -p "Commit Message: " commit_msg read -r -e -p "Commit Message: " commit_msg
fi fi
if [ -n "$commit_msg" ]; then if [ -z "$commit_msg" ]; then
eval $@ # run any prequisite commands if [ -n "$saved_commit_msg" ]; then
# Add $APPEND to commit message, if given. (Used to append things like [ci skip] for Travis CI) commit_msg="$saved_commit_msg"
if [ -n "$APPEND" ]; then commit_msg="$commit_msg $APPEND"; fi
echo $commit_msg | git commit -F - | tail -n +2
else else
echo -e "\033[0;31mAborting commit due to empty commit message.\033[0m" echo -e "\033[0;31mAborting commit due to empty commit message.\033[0m"
return
fi
fi fi
escaped=$(echo "$commit_msg" | sed -e 's/"/\\"/g' -e 's/!/"'"'"'!'"'"'"/g')
# Add $GIT_COMMIT_MSG_SUFFIX to commit message, if given.
# (Used to append things like [ci skip] for Travis CI)
if [ -n "$GIT_COMMIT_MSG_SUFFIX" ]; then
commit_msg="$commit_msg $GIT_COMMIT_MSG_SUFFIX"
fi
# Exclamation marks are really difficult to escape properly in a bash prompt.
# They must always be enclosed with single quotes.
escaped_msg=$(echo "$commit_msg" | sed -e 's/"/\\"/g' -e "s/!/\"'!'\"/g")
# Add command to bash history, so that if a git pre-commit hook fails,
# you can just press "up" and "return" to retry the commit.
if [[ $shell == "zsh" ]]; then if [[ $shell == "zsh" ]]; then
print -s "git commit -m \"${escaped//\\/\\\\}\"" # zsh's print needs double escaping # zsh's print needs double escaping
print -s "$commit_msg" print -s "git commit -m \"${escaped_msg//\\/\\\\}\""
else else
echo "git commit -m \"$escaped\"" >> $HISTFILE history -s "git commit -m \"$escaped_msg\""
# Also add unescaped commit message, for git prompt # Need to write history to a file for tests
echo "$commit_msg" >> $HISTFILE if [ -n "$SHUNIT_VERSION" ]; then history -w $HISTFILE; fi
fi
# Also save the commit message to a temp file in case git commit fails
echo "$commit_msg" > "/tmp/.git_commit_message~"
eval $@ # run any prequisite commands
echo "$commit_msg" | git commit -F - | tail -n +2
# Fetch the pipe status (for both bash and zsh):
GIT_PIPE_STATUS=("${PIPESTATUS[@]}${pipestatus[@]}")
if [[ $shell == "zsh" ]]; then
git_exit_status="${GIT_PIPE_STATUS[2]}" # zsh array indexes start at 1
else
git_exit_status="${GIT_PIPE_STATUS[1]}"
fi
if [[ "$git_exit_status" == 0 ]]; then
# Delete saved commit message if commit was successful
rm -f "/tmp/.git_commit_message~"
fi fi
} }
@@ -234,8 +275,8 @@ git_commit_all() {
fail_if_not_git_repo || return 1 fail_if_not_git_repo || return 1
changes=$(git status --porcelain | wc -l | tr -d ' ') changes=$(git status --porcelain | wc -l | tr -d ' ')
if [ "$changes" -gt 0 ]; then if [ "$changes" -gt 0 ]; then
if [ -n "$APPEND" ]; then if [ -n "$GIT_COMMIT_MSG_SUFFIX" ]; then
local appending=" | \033[0;36mappending '\033[1;36m$APPEND\033[0;36m' to commit message.\033[0m" local appending=" | \033[0;36mappending '\033[1;36m$GIT_COMMIT_MSG_SUFFIX\033[0;36m' to commit message.\033[0m"
fi fi
echo -e "\033[0;33mCommitting all files (\033[0;31m$changes\033[0;33m)\033[0m$appending" echo -e "\033[0;33mCommitting all files (\033[0;31m$changes\033[0;33m)\033[0m$appending"
git_commit_prompt "git add --all ." git_commit_prompt "git add --all ."

View File

@@ -0,0 +1,328 @@
#!/usr/bin/env ruby
# encoding: UTF-8
# ------------------------------------------------------------------------------
# SCM Breeze - Streamline your SCM workflow.
# Copyright 2011 Nathan Broadbent (http://madebynathan.com). All Rights Reserved.
# Released under the LGPL (GNU Lesser General Public License)
# ------------------------------------------------------------------------------
#
# Original work by Nathan Broadbent
# Rewritten by LFDM
#
# A much faster implementation of git_status_shortcuts() in ruby
# (original benchmarks - bash: 0m0.549s, ruby: 0m0.045s, the updated
# version is twice as fast, especially noticable in big repos)
#
#
# Last line of output contains the ordered absolute file paths,
# which need to be extracted by the shell and exported as numbered env variables.
#
# Processes 'git status', and exports numbered
# env variables that contain the path of each affected file.
# Output is also more concise than standard 'git status'.
#
# Call with optional <group> parameter to just show one modification state
# # groups => 1: staged, 2: unmerged, 3: unstaged, 4: untracked
# --------------------------------------------------------------------
#
require 'strscan'
class GitStatus
def initialize(request = nil)
@request = request.to_s # capture nils
@status = get_status
@ahead, @behind = parse_remote_stat
@grouped_changes = parse_changes
@index = 0
end
def report
exit if all_changes.length > ENV["gs_max_changes"].to_i
print_header
print_groups
puts filelist if @grouped_changes.any?
end
######### Parsing methods #########
def get_status
`git status 2>/dev/null`
end
# Remote info is always on the second line of git status
def parse_remote_stat
remote_line = @status.lines[1].strip
if remote_line.match(/diverged/)
remote_line.match(/.*(\d*).*(\d*)/).captures
else
[remote_line[/is ahead of.*by (\d*).*/, 1], remote_line[/is behind.*by (\d*).*/, 1]]
end
end
# We have to resort to the StringScanner to stay away from overly complex
# regular expressions.
# The individual blocks are always formatted the same
#
# identifier Changes not staged for commit
# helper text (use "git add <file>..." ...
# empty line
# changed files, leaded by a tab modified: file
# deleted: other_file
# empty line
# next identifier Untracked files
# ...
#
# We parse each requested group and return a grouped hash, its values are
# arrays of GitChange objects.
def parse_changes
scanner = StringScanner.new(@status)
requested_groups.each_with_object({}) do |(type, identifier), h|
if scanner.scan_until(/#{identifier}/)
scan_until_next_empty_line(scanner)
file_block = scan_until_next_empty_line(scanner)
h[type] = extract_changes(file_block)
end
scanner.reset
end
end
def scan_until_next_empty_line(scanner)
scanner.scan_until(/\n\n/)
end
# Matches
# modified: file # usual output in git status
# modified: file (untracked content) # output for submodules
# file # untracked files have no additional info
def extract_changes(str)
str.lines.map do |line|
new_git_change(*Regexp.last_match.captures) if line.match(/\t(.*:)?(.*)/)
end.compact # in case there were any non matching lines left
end
def new_git_change(status, file_and_message)
status = 'untracked:' unless status
GitChange.new(file_and_message, status)
end
GROUPS = {
staged: 'Changes to be committed',
unmerged: 'Unmerged paths',
unstaged: 'Changes not staged for commit',
untracked: 'Untracked files'
}
# Returns all possible groups when there was no request at all,
# otherwise selects groups by name or integer
def requested_groups
@request.empty? ? GROUPS : select_groups
end
def select_groups
req = parse_request
GROUPS.select { |k, _| k == req }
end
def parse_request
if @request.match(/\d/)
GROUPS.keys[@request.to_i - 1]
else
@request.to_sym
end
end
######### Outputting methods #########
def print_header
puts delimiter(:header) + header
puts delimiter(:header) if anything_changed?
end
def print_groups
@grouped_changes.each do |type, changes|
print_group_header(type)
puts delimiter(type)
changes.each do |change|
raise_index!
print delimiter(type)
puts change.report_with_index(@index, type, padding)
end
puts delimiter(type)
end
end
def print_group_header(type)
puts "#{gmu('➤', type, 1)} #{GROUPS[type]}"
end
######### Items of interest #########
def branch
@status.lines.first.strip[/^On branch (.*)$/, 1]
end
def ahead
"+#{@ahead}" if @ahead
end
def behind
"-#{@behind}" if @behind
end
def difference
[behind, ahead].compact.join('/')
end
def header
parts = [[:branch, :branch], [:difference, :new]]
parts << (anything_changed? ? [:hotkey, :dark] : [:clean_state, :mod]) # mod is green
# compact because difference might return nil
"On branch: #{parts.map { |meth, col| mu(send(meth), col) }.compact.join(' | ')}"
end
def clean_state
"No changes (working directory clean)"
end
def hotkey
"[*] => $#{ENV['git_env_char']}"
end
# used to delimit the left side of the screen - looks nice
def delimiter(col)
gmu("# ", col)
end
def filelist
"@@filelist@@::#{all_changes.map(&:absolute_path).join('|')}"
end
######### Helper Methods #########
# To know about changes we could ask if there are any parsing results, as in
# @grouped_changes.any?, but that is not a good idea, since
# we might have selected a requested group before parsing already.
# Groups could be empty while there are in fact changes present,
# there we look into the original status string once
def anything_changed?
@any_changes ||=
! @status.match(/nothing to commit.*working directory clean/)
end
# needed by hotkey filelist
def raise_index!
@index += 1
end
def all_changes
@all_changes ||= @grouped_changes.values.flatten
end
# Dynamic padding, always looks for the longest status string present
# and adds a little whitespace
def padding
@padding ||= all_changes.map { |change| change.status.size }.max + 5
end
######### Markup/Color methods #########
COL = {
:rst => "0",
:header => "0",
:branch => "1",
:del => "0;31",
:mod => "0;32",
:new => "0;33",
:ren => "0;34",
:cpy => "0;33",
:typ => "0;35",
:unt => "0;36",
:dark => "2;37",
}
GR_COL = {
:staged => "33",
:unmerged => "31",
:unstaged => "32",
:untracked => "36",
}
# markup
def mu(str, col_in, col_out = :rst)
return if str.empty?
col_in = "\033[#{COL[col_in]}m"
col_out = "\033[#{COL[col_out]}m"
with_color(str, col_in, col_out)
end
# group markup
def gmu(str, group, boldness = 0, col_out = :rst)
group_col = "\033[#{boldness};#{GR_COL[group]}m"
col_out = "\033[#{COL[col_out]}m"
with_color(str, group_col, col_out)
end
def with_color(str, col_in, col_out)
"#{col_in}#{str}#{col_out}"
end
end
class GitChange < GitStatus
attr_reader :status
# Restructively singles out the submodules message and
# strips the remaining string to get rid of padding
def initialize(file_and_message, status)
@message = file_and_message.slice!(/\(.*\)/)
@file = file_and_message.strip
@file = (@file.include? " ") ? "\"#{@file}\"" : @file
@status = status.strip
end
def absolute_path
File.expand_path(@file, Dir.pwd)
end
STATUS_COLORS = {
"copied" => :cpy,
"both deleted" => :del,
"deleted by us" => :del,
"deleted by them" => :del,
"deleted" => :del,
"both modified" => :mod,
"modified" => :mod,
"added by them" => :new,
"added by us" => :new,
"both added" => :new,
"new file" => :new,
"renamed" => :ren,
"typechange" => :typ,
"untracked" => :unt,
}
# Looks like this
#
# PADDING STATUS INDEX FILE MESSAGE (optional)
# modified: [1] changed_file (untracked content)
#
def report_with_index(index, type, padding = 0)
"#{pad(padding)}#{mu(@status, color_key)} " +
"#{mu("[#{index}]", :dark)} #{gmu(@file, type)} #{@message}"
end
# we most likely have a : with us which we don't need here
def color_key
STATUS_COLORS[@status.chomp(':')]
end
def pad(padding)
' ' * (padding - @status.size)
end
end
GitStatus.new(ARGV.first).report

View File

@@ -23,8 +23,9 @@ git_remove_history() {
return return
fi fi
# Remove all paths passed as arguments from the history of the repo # Remove all paths passed as arguments from the history of the repo
files=$@ local files
$_git_cmd filter-branch --index-filter "$_git_cmd rm -rf --cached --ignore-unmatch $files" HEAD files=("$@")
$_git_cmd filter-branch --index-filter "$_git_cmd rm -rf --cached --ignore-unmatch ${files[*]}" HEAD
# Remove the temporary history git-filter-branch otherwise leaves behind for a long time # Remove the temporary history git-filter-branch otherwise leaves behind for a long time
rm -rf .git/refs/original/ && $_git_cmd reflog expire --all && $_git_cmd gc --aggressive --prune rm -rf .git/refs/original/ && $_git_cmd reflog expire --all && $_git_cmd gc --aggressive --prune
} }

View File

@@ -18,6 +18,48 @@ _alias() {
fi fi
} }
# Quote the contents of "$@"
function token_quote {
# Older versions of {ba,z}sh don't support the built-in quoting, so fall back to printf %q
local quoted
quoted=() # Assign separately for zsh 5.0.2 of Ubuntu 14.04
for token; do
quoted+=( "$(printf '%q' "$token")" )
done
printf '%s\n' "${quoted[*]}"
# Keep this code for use when minimum versions of {ba,z}sh can be increased.
# See https://github.com/scmbreeze/scm_breeze/issues/260
#
# if [[ $shell = bash ]]; then
# # ${parameter@operator} where parameter is ${@} and operator is 'Q'
# # https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
# eval "${@@Q}"
# else # zsh
# # http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion-Flags
# eval "${(q-)@}"
# fi
}
# Quote "$@" before `eval` to prevent arbitrary code execution.
# Eg, the following will run `date`:
# evil() { eval "$@"; }; evil "echo" "foo;date"
function _safe_eval() {
eval $(token_quote "$@")
# Keep this code for use when minimum versions of {ba,z}sh can be increased.
# See https://github.com/scmbreeze/scm_breeze/issues/260
#
# if [[ $shell = bash ]]; then
# # ${parameter@operator} where parameter is ${@} and operator is 'Q'
# # https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
# eval "${@@Q}"
# else # zsh
# # http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion-Flags
# eval "${(q-)@}"
# fi
}
find_binary(){ find_binary(){
if [ $shell = "zsh" ]; then if [ $shell = "zsh" ]; then
builtin type -p "$1" | sed "s/$1 is //" | head -1 builtin type -p "$1" | sed "s/$1 is //" | head -1

View File

@@ -3,8 +3,16 @@
failed=false failed=false
# allow list of shells to run tests in to be overriden by environment variable
# if empty or null, use defaults
if [ -z "$TEST_SHELLS" ]; then
TEST_SHELLS="bash zsh"
fi
echo "== Will run all tests with following shells: ${TEST_SHELLS}"
cd -P -- "${0%/*}" # Change to directory this script lives in
for test in $(find test/lib -name *_test.sh); do for test in $(find test/lib -name *_test.sh); do
for shell in bash zsh; do for shell in $TEST_SHELLS; do
echo "== Running tests with [$shell]: $test" echo "== Running tests with [$shell]: $test"
$shell $test || failed=true $shell $test || failed=true
done done

View File

@@ -22,6 +22,7 @@ if [[ -s "$HOME/.git.scmbrc" ]]; then
source "$scmbDir/lib/git/keybindings.sh" source "$scmbDir/lib/git/keybindings.sh"
source "$scmbDir/lib/git/status_shortcuts.sh" source "$scmbDir/lib/git/status_shortcuts.sh"
source "$scmbDir/lib/git/branch_shortcuts.sh" source "$scmbDir/lib/git/branch_shortcuts.sh"
source "$scmbDir/lib/git/grep_shortcuts.sh"
source "$scmbDir/lib/git/shell_shortcuts.sh" source "$scmbDir/lib/git/shell_shortcuts.sh"
source "$scmbDir/lib/git/repo_index.sh" source "$scmbDir/lib/git/repo_index.sh"
source "$scmbDir/lib/git/tools.sh" source "$scmbDir/lib/git/tools.sh"

View File

@@ -7,10 +7,14 @@
# #
# Unit tests for git shell scripts # Unit tests for git shell scripts
export scmbDir="$( cd -P "$( dirname "$0" )" && pwd )/../../.." export scmbDir="$(cd -P "$(dirname "$0")" && pwd)/../../.."
# Zsh compatibility # Zsh compatibility
if [ -n "${ZSH_VERSION:-}" ]; then shell="zsh"; SHUNIT_PARENT=$0; setopt shwordsplit; fi if [ -n "${ZSH_VERSION:-}" ]; then
shell="zsh"
SHUNIT_PARENT=$0
setopt shwordsplit
fi
# Load test helpers # Load test helpers
source "$scmbDir/test/support/test_helper.sh" source "$scmbDir/test/support/test_helper.sh"
@@ -19,7 +23,6 @@ source "$scmbDir/test/support/test_helper.sh"
source "$scmbDir/lib/scm_breeze.sh" source "$scmbDir/lib/scm_breeze.sh"
source "$scmbDir/lib/git/repo_index.sh" source "$scmbDir/lib/git/repo_index.sh"
# Setup and tear down # Setup and tear down
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
oneTimeSetUp() { oneTimeSetUp() {
@@ -34,7 +37,10 @@ oneTimeSetUp() {
cd $GIT_REPO_DIR cd $GIT_REPO_DIR
# Setup test repos in temp repo dir # Setup test repos in temp repo dir
for repo in github bitbucket source_forge TestCaps; do for repo in github bitbucket source_forge TestCaps; do
mkdir $repo; cd $repo; git init; cd - > /dev/null mkdir $repo
cd $repo
git init
cd - >/dev/null
done done
# Add some nested dirs for testing resursive tab completion # Add some nested dirs for testing resursive tab completion
@@ -47,7 +53,7 @@ oneTimeSetUp() {
mkdir submodules_everywhere mkdir submodules_everywhere
cd submodules_everywhere cd submodules_everywhere
git init git init
cat > .gitmodules <<EOF cat >.gitmodules <<EOF
[submodule "very/nested/directory/red_submodule"] [submodule "very/nested/directory/red_submodule"]
[submodule "very/nested/directory/green_submodule"] [submodule "very/nested/directory/green_submodule"]
[submodule "very/nested/directory/blue_submodule"] [submodule "very/nested/directory/blue_submodule"]
@@ -55,15 +61,19 @@ EOF
mkdir -p "very/nested/directory" mkdir -p "very/nested/directory"
cd "very/nested/directory" cd "very/nested/directory"
for repo in red_submodule green_submodule blue_submodule; do for repo in red_submodule green_submodule blue_submodule; do
mkdir $repo; cd $repo; git init; cd - > /dev/null mkdir $repo
cd $repo
git init
cd - >/dev/null
done done
# Setup some custom repos outside the main repo dir # Setup some custom repos outside the main repo dir
IFS=":" local IFS=":"
for dir in $GIT_REPOS; do for dir in $GIT_REPOS; do
mkdir -p $dir; cd $dir; git init; mkdir -p $dir
cd $dir
git init
done done
unset IFS
verboseGitCommands verboseGitCommands
@@ -72,9 +82,8 @@ EOF
oneTimeTearDown() { oneTimeTearDown() {
rm -rf "${GIT_REPO_DIR}" rm -rf "${GIT_REPO_DIR}"
IFS=":" local IFS=":"
for dir in $GIT_REPOS; do rm -rf $dir; done for dir in $GIT_REPOS; do rm -rf $dir; done
unset IFS
} }
ensureIndex() { ensureIndex() {
@@ -85,30 +94,32 @@ index_no_newlines() {
tr "\\n" " " < $git_index_file tr "\\n" " " < $git_index_file
} }
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# Unit tests # Unit tests
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
test_repo_index_command() { test_repo_index_command() {
git_index --rebuild > /dev/null git_index --rebuild >/dev/null
# Test that all repos are detected, and sorted alphabetically # Test that all repos are detected, and sorted alphabetically
assertIncludes "$(index_no_newlines)" "bitbucket.*\ assertIncludes "$(index_no_newlines)" $(
blue_submodule.*\ cat <<EXPECT | sort -t "." -k1,1 | tr -d '\n' | awk '{print ".*"$1}'
github.*\ bitbucket.*
green_submodule.*\ blue_submodule.*
red_submodule.*\ github.*
source_forge.*\ green_submodule.*
submodules_everywhere.*\ red_submodule.*
test_repo_11.*\ source_forge.*
test_repo_1" submodules_everywhere.*
test_repo_11.*
test_repo_1.*
EXPECT
)
} }
test_check_git_index() { test_check_git_index() {
ensureIndex ensureIndex
echo "should not be regenerated" >> $git_index_file echo "should not be regenerated" >>$git_index_file
_check_git_index _check_git_index
# Test that index is not rebuilt unless empty # Test that index is not rebuilt unless empty
assertIncludes "$(index_no_newlines)" "should not be regenerated" assertIncludes "$(index_no_newlines)" "should not be regenerated"
@@ -133,16 +144,26 @@ test_repo_list() {
# Test matching rules for changing directory # Test matching rules for changing directory
test_git_index_changing_directory() { test_git_index_changing_directory() {
ensureIndex ensureIndex
git_index "github"; assertEquals "$GIT_REPO_DIR/github" "$PWD" git_index "github"
git_index "github/"; assertEquals "$GIT_REPO_DIR/github" "$PWD" assertEquals "$GIT_REPO_DIR/github" "$PWD"
git_index "bucket"; assertEquals "$GIT_REPO_DIR/bitbucket" "$PWD" git_index "github/"
git_index "testcaps"; assertEquals "$GIT_REPO_DIR/TestCaps" "$PWD" assertEquals "$GIT_REPO_DIR/github" "$PWD"
git_index "green_sub"; assertEquals "$GIT_REPO_DIR/submodules_everywhere/very/nested/directory/green_submodule" "$PWD" git_index "bucket"
git_index "_submod"; assertEquals "$GIT_REPO_DIR/submodules_everywhere/very/nested/directory/blue_submodule" "$PWD" assertEquals "$GIT_REPO_DIR/bitbucket" "$PWD"
git_index "test_repo_1"; assertEquals "/tmp/test_repo_1" "$PWD" git_index "testcaps"
git_index "test_repo_11"; assertEquals "/tmp/test_repo_11" "$PWD" assertEquals "$GIT_REPO_DIR/TestCaps" "$PWD"
git_index "test_repo_"; assertEquals "/tmp/test_repo_11" "$PWD" git_index "green_sub"
git_index "github/videos/octocat/live_action"; assertEquals "$GIT_REPO_DIR/github/videos/octocat/live_action" "$PWD" assertEquals "$GIT_REPO_DIR/submodules_everywhere/very/nested/directory/green_submodule" "$PWD"
git_index "_submod"
assertEquals "$GIT_REPO_DIR/submodules_everywhere/very/nested/directory/blue_submodule" "$PWD"
git_index "test_repo_1"
assertEquals "/tmp/test_repo_1" "$PWD"
git_index "test_repo_11"
assertEquals "/tmp/test_repo_11" "$PWD"
git_index "test_repo_"
assertEquals "/tmp/test_repo_1" "$PWD"
git_index "github/videos/octocat/live_action"
assertEquals "$GIT_REPO_DIR/github/videos/octocat/live_action" "$PWD"
} }
test_git_index_tab_completion() { test_git_index_tab_completion() {
@@ -172,7 +193,6 @@ test_git_index_tab_completion() {
_git_index_tab_completion _git_index_tab_completion
assertIncludes "$(tab_completions)" "github/videos/octocat/" assertIncludes "$(tab_completions)" "github/videos/octocat/"
# Test that completion checks for other matching projects even if one matches perfectly # Test that completion checks for other matching projects even if one matches perfectly
COMP_WORDS="test_repo_1" COMP_WORDS="test_repo_1"
_git_index_tab_completion _git_index_tab_completion
@@ -180,7 +200,6 @@ test_git_index_tab_completion() {
fi fi
} }
# Test changing to top-level directory (when arg begins with '/') # Test changing to top-level directory (when arg begins with '/')
test_changing_to_top_level_directory() { test_changing_to_top_level_directory() {
mkdir "$GIT_REPO_DIR/gems" mkdir "$GIT_REPO_DIR/gems"
@@ -188,8 +207,6 @@ test_changing_to_top_level_directory() {
assertEquals "$GIT_REPO_DIR/gems" "$PWD" assertEquals "$GIT_REPO_DIR/gems" "$PWD"
} }
# load and run shUnit2 # load and run shUnit2
# Call this function to run tests # Call this function to run tests
source "$scmbDir/test/support/shunit2" source "$scmbDir/test/support/shunit2"

View File

@@ -31,12 +31,16 @@ oneTimeSetUp() {
alias rvm="test" # Ensure tests run if RVM isn't loaded but $HOME/.rvm is present alias rvm="test" # Ensure tests run if RVM isn't loaded but $HOME/.rvm is present
# Test functions # Test functions
function ln() { ln $@; } function ln() { ln "$@"; }
# Before aliasing, get original locations so we can compare them in the test
unalias mv rm sed cat 2>/dev/null
export mv_path="$(bin_path mv)"
export rm_path="$(bin_path rm)"
export sed_path="$(bin_path sed)"
export cat_path="$(bin_path cat)"
# Test aliases # Test aliases
export mv_path="$(which mv)"
export rm_path="$(which rm)"
export sed_path="$(which sed)"
export cat_pathj="$(which cat)"
alias mv="nocorrect $mv_path" alias mv="nocorrect $mv_path"
alias rm="$rm_path --option" alias rm="$rm_path --option"
alias sed="$sed_path" alias sed="$sed_path"
@@ -58,13 +62,22 @@ assertAliasEquals(){
} }
#-----------------------------------------------------------------------------
# Setup and tear down
#-----------------------------------------------------------------------------
setUp() {
unset QUOTING_STYLE # Use default quoting style for ls
}
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# Unit tests # Unit tests
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
test_shell_command_wrapping() { test_shell_command_wrapping() {
assertAliasEquals "exec_scmb_expand_args $rm_path --option" "rm"
assertAliasEquals "exec_scmb_expand_args nocorrect $mv_path" "mv" assertAliasEquals "exec_scmb_expand_args nocorrect $mv_path" "mv"
assertAliasEquals "exec_scmb_expand_args $rm_path --option" "rm"
assertAliasEquals "exec_scmb_expand_args $sed_path" "sed" assertAliasEquals "exec_scmb_expand_args $sed_path" "sed"
assertAliasEquals "exec_scmb_expand_args $cat_path" "cat" assertAliasEquals "exec_scmb_expand_args $cat_path" "cat"
assertAliasEquals "exec_scmb_expand_args builtin cd" "cd" assertAliasEquals "exec_scmb_expand_args builtin cd" "cd"
@@ -76,18 +89,26 @@ test_ls_with_file_shortcuts() {
export git_env_char="e" export git_env_char="e"
TEST_DIR=$(mktemp -d -t scm_breeze.XXXXXXXXXX) TEST_DIR=$(mktemp -d -t scm_breeze.XXXXXXXXXX)
cd $TEST_DIR
# Darwin actually symlinks /var inside /private, but mktemp reports back the
# logical pathat time of file creation. So make sure we always get the
# full physical path to be absolutely certain when doing comparisons later,
# because thats how the Ruby status_shortcuts.rb script is going to obtain
# them.
cd "$TEST_DIR"
TEST_DIR=$(pwd -P)
touch 'test file' 'test_file' touch 'test file' 'test_file'
mkdir -p "a [b]" 'a "b"' "a 'b'" mkdir -p "a [b]" 'a "b"' "a 'b'"
touch "a \"b\"/c" touch 'a "b"/c'
# Run command in shell, load output from temp file into variable # Run command in shell, load output from temp file into variable
# (This is needed so that env variables are exported in the current shell) # (This is needed so that env variables are exported in the current shell)
temp_file=$(mktemp -t scm_breeze.XXXXXXXXXX) temp_file=$(mktemp -t scm_breeze.XXXXXXXXXX)
ls_with_file_shortcuts > $temp_file ls_with_file_shortcuts > "$temp_file"
ls_output=$(<$temp_file strip_colors) ls_output=$(<"$temp_file" strip_colors)
# Compare as fixed strings (F), instead of regex (P) # Compare as fixed strings (F), instead of normal grep behavior
assertIncludes "$ls_output" '[1] a "b"' F assertIncludes "$ls_output" '[1] a "b"' F
assertIncludes "$ls_output" "[2] a 'b'" F assertIncludes "$ls_output" "[2] a 'b'" F
assertIncludes "$ls_output" '[3] a [b]' F assertIncludes "$ls_output" '[3] a [b]' F
@@ -106,10 +127,24 @@ test_ls_with_file_shortcuts() {
ls_output=$(<$temp_file strip_colors) ls_output=$(<$temp_file strip_colors)
assertIncludes "$ls_output" '[1] c' F assertIncludes "$ls_output" '[1] c' F
# Test that env variable is set correctly # Test that env variable is set correctly
assertEquals "$TEST_DIR/a \"b\"/c" "$e1" assertEquals "$TEST_DIR/"'a "b"/c' "$e1"
# Test arg with no quotes # Test arg with no quotes
ls_output=$(ls_with_file_shortcuts a\ \"b\" | strip_colors) ls_output=$(ls_with_file_shortcuts a\ \"b\" | strip_colors)
assertIncludes "$ls_output" '[1] c' F assertIncludes "$ls_output" '[1] c' F
# Listing two directories fails (see issue #275)
mkdir 1 2
touch 1/file
assertFalse 'Only one directory supported' 'ls_with_file_shortcuts 1 2'
assertFalse 'Fails on <directory> <file>' 'ls_with_file_shortcuts 1 test_file'
assertFalse 'Fails on <file> <directory>' 'ls_with_file_shortcuts test_file 1'
assertFalse 'Fails on <directory> <directory>/<file>' 'ls_with_file_shortcuts 1 1/file'
# Files under the root directory
assertTrue 'Shortcuts under /' 'ls_with_file_shortcuts / > /dev/null && [[ $e1 =~ ^/[^/]+$ ]]'
cd -
rm -r "$TEST_DIR" "$temp_file"
} }
# load and run shUnit2 # load and run shUnit2

View File

@@ -29,6 +29,7 @@ oneTimeSetUp() {
export ga_auto_remove="yes" export ga_auto_remove="yes"
testRepo=$(mktemp -d -t scm_breeze.XXXXXXXXXX) testRepo=$(mktemp -d -t scm_breeze.XXXXXXXXXX)
testRepo=$(cd $testRepo && pwd -P)
} }
oneTimeTearDown() { oneTimeTearDown() {
@@ -48,21 +49,72 @@ setupTestRepo() {
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
test_scmb_expand_args() { test_scmb_expand_args() {
local e1="one"; local e2="two"; local e3="three"; local e4="four"; local e5="five"; local e6="six"; local e7="seven" local e1="one" e2="two" e3="three" e4="four" e5="five" e6="six" e7='$dollar' e8='two words'
local error="Args not expanded correctly" local error="Args not expanded correctly"
assertEquals "$error" "$(printf 'one\tthree\tseven')" "$(scmb_expand_args 1 3 7)" assertEquals "$error" 'one three six' \
assertEquals "$error" "$(printf 'one\ttwo\tthree\tsix')" "$(scmb_expand_args 1-3 6)" "$(eval args="$(scmb_expand_args 1 3 6)"; token_quote "${args[@]}")"
assertEquals "$error" "$(printf 'seven\ttwo\tthree\tfour\tfive\tone')" "$(scmb_expand_args seven 2-5 1)" assertEquals "$error" 'one two three five' \
"$(eval args="$(scmb_expand_args 1-3 5)"; token_quote "${args[@]}")"
assertEquals "$error" '\$dollar two three four one' \
"$(eval args="$(scmb_expand_args 7 2-4 1)"; token_quote "${args[@]}")"
# Test that any args with spaces remain quoted # Test that any args with spaces remain quoted
assertEquals "$error" "$(printf -- '-m\tTest Commit Message\tone')" "$(scmb_expand_args -m "Test Commit Message" 1)" assertEquals "$error" '-m Test\ Commit\ Message one' \
assertEquals "$error" "$(printf -- '-ma\tTest Commit Message\tUnquoted')"\ "$(eval args="$(scmb_expand_args -m "Test Commit Message" 1)"; token_quote "${args[@]}")"
"$(scmb_expand_args -ma "Test Commit Message" "Unquoted")" assertEquals "$error" '-ma Test\ Commit\ Message Unquoted'\
"$(eval args="$(scmb_expand_args -ma "Test Commit Message" "Unquoted")"; token_quote "${args[@]}")"
assertEquals "$error" '\$dollar one two\ words' \
"$(eval args="$(scmb_expand_args 7 1-1 8)"; token_quote "${args[@]}")"
# Keep this code for use when minimum versions of {ba,z}sh can be increased.
# See token_quote() source and https://github.com/scmbreeze/scm_breeze/issues/260
# local e1="one" e2="two" e3="three" e4="four" e5="five" e6="six" e7='$dollar' e8='two words'
# local error="Args not expanded correctly"
# assertEquals "$error" "'one' 'three' 'six'" \
# "$(eval a=$(scmb_expand_args 1 3 6); token_quote "${a[@]}")"
# assertEquals "$error" "'one' 'two' 'three' 'five'" \
# "$(eval a=$(scmb_expand_args 1-3 5); token_quote "${a[@]}")"
# assertEquals "$error" "'\$dollar' 'two' 'three' 'four' 'one'" \
# "$(eval a=$(scmb_expand_args 7 2-4 1); token_quote "${a[@]}")"
#
# # Test that any args with spaces remain quoted
# assertEquals "$error" "'-m' 'Test Commit Message' 'one'" \
# "$(eval a=$(scmb_expand_args -m "Test Commit Message" 1); token_quote "${a[@]}")"
# assertEquals "$error" "'-ma' 'Test Commit Message' 'Unquoted'"\
# "$(eval a=$(scmb_expand_args -ma "Test Commit Message" "Unquoted"); token_quote "${a[@]}")"
# assertEquals "$error" "'\$dollar' 'one' 'two words'" \
# "$(eval a=$(scmb_expand_args 7 1-1 8); token_quote "${a[@]}")"
}
test_exec_scmb_expand_args() {
local e1="one" e2="a b c" e3='$dollar' e4="single'quote" e5='double"quote' e6='a(){:;};a&'
assertEquals "literals with spaces not preserved" 'foo bar\ baz' \
"$(eval args="$(scmb_expand_args foo 'bar baz')"; token_quote "${args[@]}")"
assertEquals "variables with spaces not preserved" 'one a\ b\ c' \
"$(eval args="$(scmb_expand_args 1-2)"; token_quote "${args[@]}")"
# Expecting text: '$dollar' "single'quote" 'double"quote'
# Generate quoted expected string with: token_quote "$(cat)" then copy/paste, ^D
assertEquals "special characters are preserved" \
'\$dollar single\'\''quote double\"quote a\(\)\{:\;\}\;a\&' \
"$(eval args="$(scmb_expand_args 3-6)"; token_quote "${args[@]}")"
# Keep this code for use when minimum versions of {ba,z}sh can be increased.
# See token_quote() source and https://github.com/scmbreeze/scm_breeze/issues/260
# local e1="one" e2="a b c" e3='$dollar' e4="single'quote" e5='double"quote' e6='a(){:;};a&'
# assertEquals "literals with spaces not preserved" "'foo' 'bar baz'" \
# "$(eval a="$(scmb_expand_args foo 'bar baz')"; token_quote "${a[@]}")"
# assertEquals "variables with spaces not preserved" "'one' 'a b c'" \
# "$(eval a="$(scmb_expand_args 1-2)"; token_quote "${a[@]}")"
# # Expecting text: '$dollar' "single'quote" 'double"quote'
# # Generate quoted expected string with: token_quote "$(cat)" then copy/paste, ^D
# assertEquals "special characters are preserved" \
# "'\$dollar' 'single'\\''quote' 'double\"quote' 'a(){:;};a&'" \
# "$(eval a="$(scmb_expand_args 3-6)"; token_quote "${a[@]}")"
} }
test_command_wrapping_escapes_special_characters() { test_command_wrapping_escapes_special_characters() {
assertEquals 'should escape | the pipe' "$(exec_scmb_expand_args echo "should escape | the pipe")" assertEquals 'should escape | the pipe' "$(exec_scmb_expand_args echo should escape '|' the pipe)"
assertEquals 'should escape ; the semicolon' "$(exec_scmb_expand_args echo "should escape ; the semicolon")" assertEquals 'should escape ; the semicolon' "$(exec_scmb_expand_args echo should escape ';' the semicolon)"
} }
test_git_status_shortcuts() { test_git_status_shortcuts() {
@@ -259,9 +311,10 @@ test_git_commit_prompt() {
if [[ $shell == "zsh" ]]; then if [[ $shell == "zsh" ]]; then
test_history="$(history)" test_history="$(history)"
else else
# Need to load history from $HISTFILE
# (Couldn't get the 'history' builtin to work during tests.)
test_history="$(cat $HISTFILE)" test_history="$(cat $HISTFILE)"
fi fi
assertIncludes "$test_history" "$commit_msg"
assertIncludes "$test_history" "git commit -m \"$dbl_escaped_msg\"" assertIncludes "$test_history" "git commit -m \"$dbl_escaped_msg\""
} }
@@ -283,7 +336,7 @@ test_git_commit_prompt_with_append() {
# Test the git commit prompt, by piping a commit message # Test the git commit prompt, by piping a commit message
# instead of user input. # instead of user input.
echo "$commit_msg" | APPEND="[ci skip]" git_commit_prompt > /dev/null echo "$commit_msg" | GIT_COMMIT_MSG_SUFFIX="[ci skip]" git_commit_prompt > /dev/null
git_show_output=$(git show --oneline --name-only) git_show_output=$(git show --oneline --name-only)
assertIncludes "$git_show_output" "$commit_msg \[ci skip\]" assertIncludes "$git_show_output" "$commit_msg \[ci skip\]"

26
test/lib/scm_breeze_test.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/bash
export scmbDir="$( cd -P "$( dirname "$0" )" && pwd )/../.."
# Zsh compatibility
if [ -n "${ZSH_VERSION:-}" ]; then shell="zsh"; SHUNIT_PARENT=$0; setopt shwordsplit; fi
# Load test helpers
source "$scmbDir/test/support/test_helper.sh"
# Load functions to test
source "$scmbDir/lib/scm_breeze.sh"
#-----------------------------------------------------------------------------
# Unit tests
#-----------------------------------------------------------------------------
test__safe_eval() {
assertEquals "runs eval with simple words" 'one two three' "$(_safe_eval token_quote one two three)"
assertEquals "quotes spaces" 'a b\ c d' "$(_safe_eval token_quote a b\ c d)"
assertEquals "quotes special chars" 'a\ b \$dollar \\slash c\ d' "$(_safe_eval token_quote a\ b '$dollar' '\slash' c\ d)"
}
# load and run shUnit2
source "$scmbDir/test/support/shunit2"

View File

@@ -25,9 +25,9 @@ SHUNIT_ERROR=2
# enable strict mode by default # enable strict mode by default
SHUNIT_STRICT=${SHUNIT_STRICT:-${SHUNIT_TRUE}} SHUNIT_STRICT=${SHUNIT_STRICT:-${SHUNIT_TRUE}}
_shunit_warn() { echo "shunit2:WARN $@" >&2; } _shunit_warn() { echo "shunit2:WARN $*" >&2; }
_shunit_error() { echo "shunit2:ERROR $@" >&2; } _shunit_error() { echo "shunit2:ERROR $*" >&2; }
_shunit_fatal() { echo "shunit2:FATAL $@" >&2; exit ${SHUNIT_ERROR}; } _shunit_fatal() { echo "shunit2:FATAL $*" >&2; exit ${SHUNIT_ERROR}; }
# specific shell checks # specific shell checks
if [ -n "${ZSH_VERSION:-}" ]; then if [ -n "${ZSH_VERSION:-}" ]; then

View File

@@ -4,9 +4,9 @@ orig_cwd="$PWD"
source "$scmbDir/lib/git/helpers.sh" source "$scmbDir/lib/git/helpers.sh"
# Set up demo git user if not configured # Set up demo git user if not configured
if [ -z "$(git config --global user.email)" ]; then if [ -z "$(git config user.email)" ]; then
git config --global user.email "testuser@example.com" git config user.email "testuser@example.com"
git config --global user.name "Test User" git config user.name "Test User"
fi fi
# #
@@ -15,7 +15,8 @@ fi
# Strip color codes from a string # Strip color codes from a string
strip_colors() { strip_colors() {
sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" # Updated with info from: https://superuser.com/a/380778
perl -pe 's/\x1b\[[0-9;]*[mG]//g'
} }
# Print space separated tab completion options # Print space separated tab completion options
@@ -25,25 +26,32 @@ tab_completions(){ echo "${COMPREPLY[@]}"; }
silentGitCommands() { silentGitCommands() {
git() { /usr/bin/env git "$@" > /dev/null 2>&1; } git() { /usr/bin/env git "$@" > /dev/null 2>&1; }
} }
# Cancel silent git commands # Cancel silent git commands
verboseGitCommands() { verboseGitCommands() {
unset -f git unset -f git
} }
# Asserts # Asserts
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# Return 0 (shell's true) if "$1" contains string "$2"
_includes() { _includes() {
if [ -n "$3" ]; then regex="$3"; else regex=P; fi if [ -n "$3" ]; then regex="$3"; else regex=''; fi
if echo "$1" | grep -q$regex "$2"; then echo 0; else echo 1; fi echo "$1" | grep -q"$regex" "$2" # exit status of quiet grep is returned
} }
# assert $1 contains $2 # assert $1 contains $2
assertIncludes() { assertIncludes() {
assertTrue "'$1' should have contained '$2'" $(_includes "$@") _includes "$@"
} local grep_exit=$?
# assert $1 does not contain $2 assertTrue "'$1' should have contained '$2'" '[[ $grep_exit == 0 ]]'
assertNotIncludes() {
assertFalse "'$1' should not have contained '$2'" $(_includes "$@")
} }
# assert $1 does not contain $2
assertNotIncludes() {
_includes "$@"
local grep_return=$?
assertTrue "'$1' should not have contained '$2'" '[[ ! $grep_exit = 0 ]]'
}

32
test/support/travisci_deps.sh Executable file
View File

@@ -0,0 +1,32 @@
#!/usr/bin/env bash
# Installs dependencies for travis-ci environments.
# Install dependencies, which looks to be just bash & zsh.
#
# Darwin has zsh preinstalled already, so only need to install on Ubuntu.
#
# Note: $TRAVIS_OS_NAME will only be set on text boxes with multi-os enabled,
# so use negation test so it will fail gracefully on normal Travis linux setup.
if [[ "$TRAVIS_OS_NAME" != "osx" ]]; then
# okay, so we know we're probably on a linux box (or at least not an osx box)
# at this point. do we need to install zsh? let's say the default case is no:
needs_zsh=false
# check if zsh is listed in the TEST_SHELLS environment variable, set by
# our travis-ci build matrix.
if [[ $TEST_SHELLS =~ zsh ]]; then needs_zsh=true; fi
# if there is NO $TEST_SHELLS env variable persent (which should never happen,
# but maybe someone has been monkeying with the .travis.yml), run_tests.sh is
# going to fall back onto the default of testing everything, so we need zsh.
if [[ -z "$TEST_SHELLS" ]]; then needs_zsh=true; fi
# finally, we install zsh if needed!
if $needs_zsh; then
sudo apt-get update
sudo apt-get install zsh
else
echo "No deps required."
fi
fi

View File

@@ -1,7 +1,18 @@
#!/bin/sh #!/bin/sh
# uninstall by (github: bernardofire) # uninstall by (github: bernardofire)
# Remove line from bashrc and zshrc if present. # Remove line from bashrc and zshrc if present.
for rc in bashrc zshrc; do
sed -i '/scm_breeze/d' "$HOME/.$rc" sed="sed -i"
printf "Removed SCM Breeze from %s\n" "$HOME/.$rc" if [[ $OSTYPE == "Darwin" ]]; then
done sed="sed -i ''"
fi
if [ -f "$HOME/.bashrc" ]; then
$sed '/scm_breeze/d' "$HOME/.bashrc" &&
printf "Removed SCM Breeze from '%s'\n" "$HOME/.bashrc"
fi
if [ -f "${ZDOTDIR:-$HOME}/.zshrc" ]; then
$sed '/scm_breeze/d' "${ZDOTDIR:-$HOME}/.zshrc" &&
printf "Removed SCM Breeze from '%s'\n" "${ZDOTDIR:-$HOME}/.zshrc"
fi