├── .hgignore ├── LICENSE.markdown ├── README.markdown └── rerun /.hgignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | 3 | .DS_Store 4 | *.pyc 5 | *.swp 6 | *.swo 7 | *.un~ 8 | .ropeproject 9 | tags 10 | -------------------------------------------------------------------------------- /LICENSE.markdown: -------------------------------------------------------------------------------- 1 | MIT/X11 License 2 | =============== 3 | 4 | Copyright (c) 2011 Steve Losh and contributors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | rerun 2 | ===== 3 | 4 | `rerun` is a tiny little script that helps you run repetetive shell commands 5 | over and over again. 6 | 7 | The Problem 8 | ----------- 9 | 10 | Imagine you're working on debugging an issue with a particular daemon, like 11 | Celery. In one window you're editing code to try solutions, and in another 12 | you're stopping and starting the Celery and RabbitMQ daemons. 13 | 14 | The commands 15 | you're running over and over in varying order might look like this: 16 | 17 | sudo /etc/init.d/rabbitmq-server restart 18 | sudo /etc/init.d/celeryd stop 19 | sudo /etc/init.d/celeryd start 20 | tail /var/log/celery/myhost.log 21 | tail /var/log/celery/myotherhost.log 22 | 23 | Running the various commands can be a pain. They're similar enough that tab 24 | completion, zsh's history completion, and `Ctrl-R` searching all fall short. 25 | That's where `rerun` comes in: 26 | 27 | ![Screenshot of a rerun session](http://i.imgur.com/QcsuD.png) 28 | 29 | Installation 30 | ------------ 31 | 32 | curl 'https://raw.githubusercontent.com/mandarg/rerun/master/rerun' > /usr/local/bin/rerun 33 | chmod a+x /usr/local/bin/rerun 34 | 35 | Usage 36 | ----- 37 | 38 | When you run `rerun` you're greeted with a prompt like this: 39 | 40 | > 41 | 42 | Type `/help` (or just `/h`) to get a list of commands: 43 | 44 | > /help 45 | (/a)dd [command] 46 | (/d)elete [key] 47 | (/h)elp 48 | (/q)uit 49 | (/r)run all commands in order shown 50 | 51 | > 52 | 53 | Add commands to the list with `/add`. You can specify the command right in the 54 | `/add` command or let `rerun` prompt you for it: 55 | 56 | > /add ls 57 | 58 | [a] ls 59 | > /add 60 | Enter command: pwd 61 | 62 | [a] ls 63 | [b] pwd 64 | > 65 | 66 | Now that you've got some commands in the list, run them by entering the key 67 | displayed next to their name: 68 | 69 | [a] ls 70 | [b] pwd 71 | > a 72 | LICENSE.markdown README.markdown rerun 73 | 74 | [a] ls 75 | [b] pwd 76 | > b 77 | /Users/sjl/src/rerun 78 | 79 | [a] ls 80 | [b] pwd 81 | > 82 | 83 | If you don't need a command any more you can `/delete` it: 84 | 85 | [a] ls 86 | [b] pwd 87 | > /delete b 88 | 89 | [a] ls 90 | > /d 91 | Which command? a 92 | 93 | > 94 | 95 | You can also run all commands currently in the queue with a `/run` or `/r`: 96 | 97 | > /run 98 | /home/mandar/sandbox/rerun 99 | LICENSE.markdown README.markdown rerun 100 | 101 | [a] pwd 102 | [b] ls 103 | 104 | Use `/quit` or `Ctrl-D` to exit. 105 | 106 | Other Information 107 | ----------------- 108 | 109 | * Written by [@sjl](https://github.com/sjl), currently maintained by [@mandarg](https://github.com/mandarg) 110 | * Source (Mercurial): 111 | * Source (Git): 112 | * License: MIT/X11 113 | * Issues: 114 | -------------------------------------------------------------------------------- /rerun: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys, subprocess 4 | import readline 5 | from string import lowercase, uppercase 6 | 7 | readline.parse_and_bind("tab: complete") 8 | commands = {} 9 | 10 | def _get_key(): 11 | used = commands.keys() 12 | 13 | for c in lowercase + uppercase: 14 | if c not in used: 15 | return c 16 | 17 | return None 18 | 19 | 20 | def run(key): 21 | try: 22 | subprocess.check_call(commands[key], shell=True, stdout=sys.stdout, stderr=sys.stderr) 23 | except subprocess.CalledProcessError: 24 | return False 25 | 26 | return True 27 | 28 | def add(choice): 29 | parts = choice.split(' ', 1) 30 | 31 | if len(parts) > 1: 32 | cmd = parts[-1] 33 | else: 34 | cmd = raw_input('Enter command: ') 35 | 36 | if cmd not in commands.values(): 37 | commands[_get_key()] = cmd 38 | 39 | def delete(choice): 40 | parts = choice.split(' ', 1) 41 | 42 | if len(parts) > 1: 43 | key = parts[-1] 44 | else: 45 | key = raw_input('Which command? ') 46 | 47 | del commands[key] 48 | 49 | def copy(): 50 | # TODO 51 | pass 52 | 53 | def halp(): 54 | print "(/a)dd [command]" 55 | print "(/d)elete [key]" 56 | print "(/h)elp" 57 | print "(/q)uit" 58 | print "(/r)run all commands in order shown" 59 | 60 | 61 | def _print_list(): 62 | print 63 | for cmd in sorted(commands.items()): 64 | print '[%s] %s' % cmd 65 | 66 | 67 | def runall(): 68 | for key in sorted(commands.keys()): 69 | run(key) 70 | 71 | 72 | def loop(): 73 | _print_list() 74 | choice = raw_input('> ') 75 | 76 | if choice.startswith('/d'): 77 | delete(choice) 78 | elif choice.startswith('/a'): 79 | add(choice) 80 | elif choice.startswith('/c'): 81 | copy(choice) 82 | elif choice.startswith('/h'): 83 | halp() 84 | elif choice.startswith('/q'): 85 | return False 86 | elif choice.startswith('/r'): 87 | runall() 88 | elif not choice.strip(): 89 | pass 90 | elif choice in commands.keys(): 91 | run(choice) 92 | else: 93 | print 'Derp?' 94 | 95 | return True 96 | 97 | 98 | if __name__ == '__main__': 99 | try: 100 | while loop(): 101 | pass 102 | except EOFError: 103 | pass 104 | --------------------------------------------------------------------------------