terminitor 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +3 -0
- data/Gemfile +4 -0
- data/README.md +64 -0
- data/Rakefile +9 -0
- data/bin/terminitor +3 -0
- data/lib/terminitor.rb +30 -0
- data/lib/terminitor/runner.rb +66 -0
- data/lib/terminitor/version.rb +3 -0
- data/terminitor.gemspec +27 -0
- data/test/fixtures/foo.yml +9 -0
- data/test/terminitor_test.rb +43 -0
- data/test/teststrap.rb +58 -0
- metadata +172 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
Terminitor
|
2
|
+
===========
|
3
|
+
|
4
|
+
Terminitor automates your development workflow by allowing you to script the commands to run in your terminal to begin working on a given project.
|
5
|
+
|
6
|
+
Installation
|
7
|
+
------------
|
8
|
+
|
9
|
+
$ gem install terminitor
|
10
|
+
$ terminitor setup
|
11
|
+
|
12
|
+
Usage
|
13
|
+
-------
|
14
|
+
|
15
|
+
Using terminitor is quite easy. To define or edit a project file, simply invoke the command:
|
16
|
+
|
17
|
+
$ terminitor open foo
|
18
|
+
|
19
|
+
This will open your default editor (set by the $EDITOR variable in BASH) and you can proceed to define the commands for that project:
|
20
|
+
|
21
|
+
# ~/.terminit/foo.yml
|
22
|
+
# you can make as many tabs as you wish...
|
23
|
+
# tab names are actually arbitrary at this point too.
|
24
|
+
---
|
25
|
+
- tab1:
|
26
|
+
- cd ~/foo/bar
|
27
|
+
- gitx
|
28
|
+
- tab2:
|
29
|
+
- mysql -u root
|
30
|
+
- use test;
|
31
|
+
- show tables;
|
32
|
+
- tab3: echo "hello world"
|
33
|
+
- tab4: cd ~/baz/ && git pull
|
34
|
+
- tab5:
|
35
|
+
- cd ~/foo/project
|
36
|
+
- autotest
|
37
|
+
|
38
|
+
Simply define the tabs and declare each command. Note that the session of each tab is maintained, so you just declare actions here as
|
39
|
+
you would manually type in the terminal.
|
40
|
+
|
41
|
+
Once the project file has been declared to your satisfaction, simply execute any project defined in the @.terminit@ directory with:
|
42
|
+
|
43
|
+
$ terminitor start foo
|
44
|
+
|
45
|
+
This will execute the steps and create the tabs defined and run the various options as expected. That's it. Create as many project files with as many tabs
|
46
|
+
as you would like and automate your workflow.
|
47
|
+
|
48
|
+
Limitations
|
49
|
+
-----------
|
50
|
+
|
51
|
+
This only works on OS X because of the dependency on applescript. It would presumably not be impossible to port this to Linux or Windows, and
|
52
|
+
of course patches and suggestions are welcome.
|
53
|
+
|
54
|
+
Acknowledgements
|
55
|
+
-----------------
|
56
|
+
|
57
|
+
This code came originally years ago from: http://blog.elctech.com/2008/01/16/script-terminal-with-terminit/ .
|
58
|
+
This was a great start and made terminal automation easy. However, the repository is dead, but we had continued using the code for a while.
|
59
|
+
Finally, we decided the time had come to release this code back to the world as a gem. Thanks to ELC for creating the original
|
60
|
+
source for this project.
|
61
|
+
|
62
|
+
Also, we didn't take any code from [Project](http://github.com/joshnesbitt/project) by Josh but that project did inspire us to setup terminit
|
63
|
+
as a gem. Basically, project is a great gem but there were a couple issues with the fact that the terminal doesn't save the session state in some cases.
|
64
|
+
I had already been using terminit for years so we decided to package this up for easy use.
|
data/Rakefile
ADDED
data/bin/terminitor
ADDED
data/lib/terminitor.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'thor'
|
3
|
+
require 'appscript'
|
4
|
+
require 'yaml'
|
5
|
+
require File.expand_path('../terminitor/runner',__FILE__)
|
6
|
+
|
7
|
+
module Terminitor
|
8
|
+
class Cli < Thor
|
9
|
+
include Thor::Actions
|
10
|
+
include Terminitor::Runner
|
11
|
+
include Appscript
|
12
|
+
|
13
|
+
desc "start PROJECT_NAME", "runs the terminitor project"
|
14
|
+
def start(project)
|
15
|
+
do_project(project)
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "setup", "create initial root terminitor folder"
|
19
|
+
def setup
|
20
|
+
empty_directory "#{ENV['HOME']}/.terminitor"
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "open PROJECT_NAME", "open project yaml"
|
24
|
+
def open(project)
|
25
|
+
path = "#{ENV['HOME']}/.terminitor/#{project}.yml"
|
26
|
+
create_file path, :skip => true
|
27
|
+
open_in_editor(path)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Terminitor
|
2
|
+
module Runner
|
3
|
+
|
4
|
+
# opens doc in system designated editor
|
5
|
+
def open_in_editor(path)
|
6
|
+
`#{ENV['EDITOR']} #{path}`
|
7
|
+
end
|
8
|
+
|
9
|
+
def do_project(project)
|
10
|
+
terminal = app('Terminal')
|
11
|
+
tabs = load_config(project)
|
12
|
+
tabs.each do |hash|
|
13
|
+
tabname = hash.keys.first
|
14
|
+
cmds = hash.values.first
|
15
|
+
|
16
|
+
tab = self.open_tab(terminal)
|
17
|
+
cmds = [cmds].flatten
|
18
|
+
cmds.each do |cmd|
|
19
|
+
terminal.windows.last.do_script(cmd, :in => tab)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# def usage
|
25
|
+
# puts "
|
26
|
+
# Usage:
|
27
|
+
# #{File.basename(@file)} project_name
|
28
|
+
# where project_name is the name of a terminit project yaml file
|
29
|
+
#
|
30
|
+
# See the README for more information.
|
31
|
+
# "
|
32
|
+
# exit 0
|
33
|
+
# end
|
34
|
+
|
35
|
+
def load_config(project)
|
36
|
+
path = File.join(ENV['HOME'],'.terminitor', "#{project.sub(/\.yml$/, '')}.yml")
|
37
|
+
return false unless File.exists?(path)
|
38
|
+
YAML.load(File.read(path))
|
39
|
+
end
|
40
|
+
|
41
|
+
# somewhat hacky in that it requires Terminal to exist,
|
42
|
+
# which it would if we run this script from a Terminal,
|
43
|
+
# but it won't work if called e.g. from cron.
|
44
|
+
# The latter case would just require us to open a Terminal
|
45
|
+
# using do_script() first with no :in target.
|
46
|
+
#
|
47
|
+
# One more hack: if we're getting the first tab, we return
|
48
|
+
# the term window's only current tab, else we send a CMD+T
|
49
|
+
def open_tab(terminal)
|
50
|
+
window = has_visor? ? 2 : 1
|
51
|
+
if @got_first_tab_already
|
52
|
+
app("System Events").application_processes["Terminal.app"].keystroke("t", :using => :command_down)
|
53
|
+
end
|
54
|
+
@got_first_tab_already = true
|
55
|
+
local_window = terminal.windows[window]
|
56
|
+
local_tabs = local_window.tabs if local_window
|
57
|
+
local_tabs.last.get if local_tabs
|
58
|
+
end
|
59
|
+
|
60
|
+
# checks to see if the user has Visor installed
|
61
|
+
def has_visor?
|
62
|
+
File.exists?("#{ENV['HOME']}/Library/Application\ Support/SIMBL/Plugins/Visor.bundle/")
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
data/terminitor.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path("../lib/terminitor/version", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "terminitor"
|
6
|
+
s.version = Terminitor::VERSION
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.authors = ['Arthur Chiu', 'Nathan Esquenazi']
|
9
|
+
s.email = ['mr.arthur.chiu@gmail.com','nesquena@gmail.com']
|
10
|
+
s.homepage = "http://rubygems.org/gems/terminitor"
|
11
|
+
s.summary = "Outsource your workflow to Skynet"
|
12
|
+
s.description = "Automate your development workflow"
|
13
|
+
|
14
|
+
s.required_rubygems_version = ">= 1.3.6"
|
15
|
+
s.rubyforge_project = "terminitor"
|
16
|
+
|
17
|
+
s.add_dependency "rb-appscript"
|
18
|
+
s.add_dependency "thor", "~>0.14.0"
|
19
|
+
s.add_development_dependency "bundler", "~>1.0.0"
|
20
|
+
s.add_development_dependency "riot", "~>0.14.0"
|
21
|
+
s.add_development_dependency "rr"
|
22
|
+
s.add_development_dependency "fakefs"
|
23
|
+
|
24
|
+
s.files = `git ls-files`.split("\n")
|
25
|
+
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
26
|
+
s.require_path = 'lib'
|
27
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.expand_path('../teststrap',__FILE__)
|
2
|
+
|
3
|
+
context "Terminitor" do
|
4
|
+
setup { @yaml = File.read(File.expand_path('../fixtures/foo.yml', __FILE__)) }
|
5
|
+
setup { FakeFS.activate! }
|
6
|
+
teardown { FakeFS.deactivate! }
|
7
|
+
|
8
|
+
context "shows the help" do
|
9
|
+
setup { capture(:stdout) { Terminitor::Cli.start(['-h']) } }
|
10
|
+
asserts_topic.matches %r{start PROJECT_NAME}
|
11
|
+
asserts_topic.matches %r{setup}
|
12
|
+
asserts_topic.matches %r{open PROJECT_NAME}
|
13
|
+
end
|
14
|
+
|
15
|
+
context "setup" do
|
16
|
+
setup { capture(:stdout) { Terminitor::Cli.start(['setup']) } }
|
17
|
+
asserts("creates .terminitor") { File.exists?("#{ENV['HOME']}/.terminitor") }
|
18
|
+
end
|
19
|
+
|
20
|
+
context "open" do
|
21
|
+
setup { mock.instance_of(Terminitor::Cli).open_in_editor("#{ENV['HOME']}/.terminitor/foo.yml") { true }.once }
|
22
|
+
setup { capture(:stdout) { Terminitor::Cli.start(['open','foo']) } }
|
23
|
+
asserts_topic.matches %r{create}
|
24
|
+
end
|
25
|
+
|
26
|
+
context "start" do
|
27
|
+
setup do
|
28
|
+
@test_item = TestItem.new
|
29
|
+
@test_runner = TestRunner.new
|
30
|
+
stub(@test_runner).open_tab(anything) { true }.twice
|
31
|
+
mock(@test_item).do_script('cd /foo/bar', anything) { true }.once
|
32
|
+
mock(@test_item).do_script('gitx', anything) { true }.once
|
33
|
+
mock(@test_item).do_script('ls', anything) { true }.once
|
34
|
+
mock(@test_item).do_script('mate .', anything) { true }.once
|
35
|
+
stub(@test_runner).app('Terminal') { TestObject.new(@test_item) }
|
36
|
+
end
|
37
|
+
setup { capture(:stdout) { Terminitor::Cli.start(['setup']) } }
|
38
|
+
setup { File.open("#{ENV['HOME']}/.terminitor/foo.yml","w") { |f| f.puts @yaml } }
|
39
|
+
asserts("runs project") { @test_runner.do_project("foo") }
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
end
|
data/test/teststrap.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'riot'
|
3
|
+
require 'riot/rr'
|
4
|
+
require File.expand_path('../../lib/terminitor',__FILE__)
|
5
|
+
require 'fakefs/safe'
|
6
|
+
Riot.reporter = Riot::DotMatrixReporter
|
7
|
+
|
8
|
+
class Riot::Situation
|
9
|
+
end
|
10
|
+
|
11
|
+
class Riot::Context
|
12
|
+
end
|
13
|
+
|
14
|
+
class Object
|
15
|
+
def capture(stream)
|
16
|
+
begin
|
17
|
+
stream = stream.to_s
|
18
|
+
eval "$#{stream} = StringIO.new"
|
19
|
+
yield
|
20
|
+
result = eval("$#{stream}").string
|
21
|
+
ensure
|
22
|
+
eval("$#{stream} = #{stream.upcase}")
|
23
|
+
end
|
24
|
+
result
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class TestRunner
|
29
|
+
include Terminitor::Runner
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
class TestObject
|
34
|
+
attr_accessor :test_item
|
35
|
+
|
36
|
+
def initialize(test_item)
|
37
|
+
@test_item = test_item
|
38
|
+
end
|
39
|
+
|
40
|
+
def windows
|
41
|
+
[@test_item]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class TestItem
|
46
|
+
def do_script(prompt,hash)
|
47
|
+
true
|
48
|
+
end
|
49
|
+
|
50
|
+
def get
|
51
|
+
true
|
52
|
+
end
|
53
|
+
|
54
|
+
def keystroke(prompt,hash)
|
55
|
+
true
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
metadata
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: terminitor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Arthur Chiu
|
14
|
+
- Nathan Esquenazi
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2010-09-13 00:00:00 -07:00
|
20
|
+
default_executable:
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: rb-appscript
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 3
|
31
|
+
segments:
|
32
|
+
- 0
|
33
|
+
version: "0"
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: thor
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 39
|
45
|
+
segments:
|
46
|
+
- 0
|
47
|
+
- 14
|
48
|
+
- 0
|
49
|
+
version: 0.14.0
|
50
|
+
type: :runtime
|
51
|
+
version_requirements: *id002
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
name: bundler
|
54
|
+
prerelease: false
|
55
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ~>
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 23
|
61
|
+
segments:
|
62
|
+
- 1
|
63
|
+
- 0
|
64
|
+
- 0
|
65
|
+
version: 1.0.0
|
66
|
+
type: :development
|
67
|
+
version_requirements: *id003
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: riot
|
70
|
+
prerelease: false
|
71
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
hash: 39
|
77
|
+
segments:
|
78
|
+
- 0
|
79
|
+
- 14
|
80
|
+
- 0
|
81
|
+
version: 0.14.0
|
82
|
+
type: :development
|
83
|
+
version_requirements: *id004
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: rr
|
86
|
+
prerelease: false
|
87
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
hash: 3
|
93
|
+
segments:
|
94
|
+
- 0
|
95
|
+
version: "0"
|
96
|
+
type: :development
|
97
|
+
version_requirements: *id005
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: fakefs
|
100
|
+
prerelease: false
|
101
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
hash: 3
|
107
|
+
segments:
|
108
|
+
- 0
|
109
|
+
version: "0"
|
110
|
+
type: :development
|
111
|
+
version_requirements: *id006
|
112
|
+
description: Automate your development workflow
|
113
|
+
email:
|
114
|
+
- mr.arthur.chiu@gmail.com
|
115
|
+
- nesquena@gmail.com
|
116
|
+
executables:
|
117
|
+
- terminitor
|
118
|
+
extensions: []
|
119
|
+
|
120
|
+
extra_rdoc_files: []
|
121
|
+
|
122
|
+
files:
|
123
|
+
- .gitignore
|
124
|
+
- Gemfile
|
125
|
+
- README.md
|
126
|
+
- Rakefile
|
127
|
+
- bin/terminitor
|
128
|
+
- lib/terminitor.rb
|
129
|
+
- lib/terminitor/runner.rb
|
130
|
+
- lib/terminitor/version.rb
|
131
|
+
- terminitor.gemspec
|
132
|
+
- test/fixtures/foo.yml
|
133
|
+
- test/terminitor_test.rb
|
134
|
+
- test/teststrap.rb
|
135
|
+
has_rdoc: true
|
136
|
+
homepage: http://rubygems.org/gems/terminitor
|
137
|
+
licenses: []
|
138
|
+
|
139
|
+
post_install_message:
|
140
|
+
rdoc_options: []
|
141
|
+
|
142
|
+
require_paths:
|
143
|
+
- lib
|
144
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ">="
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
hash: 3
|
150
|
+
segments:
|
151
|
+
- 0
|
152
|
+
version: "0"
|
153
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
154
|
+
none: false
|
155
|
+
requirements:
|
156
|
+
- - ">="
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
hash: 23
|
159
|
+
segments:
|
160
|
+
- 1
|
161
|
+
- 3
|
162
|
+
- 6
|
163
|
+
version: 1.3.6
|
164
|
+
requirements: []
|
165
|
+
|
166
|
+
rubyforge_project: terminitor
|
167
|
+
rubygems_version: 1.3.7
|
168
|
+
signing_key:
|
169
|
+
specification_version: 3
|
170
|
+
summary: Outsource your workflow to Skynet
|
171
|
+
test_files: []
|
172
|
+
|