terminitor 0.0.5 → 0.1.0
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/Gemfile.lock +41 -0
- data/README.md +120 -13
- data/Termfile +11 -11
- data/lib/templates/example.term.tt +17 -0
- data/lib/terminitor.rb +13 -69
- data/lib/terminitor/abstract_core.rb +68 -0
- data/lib/terminitor/cli.rb +77 -0
- data/lib/terminitor/cores/konsole_core.rb +54 -0
- data/lib/terminitor/cores/mac_core.rb +79 -0
- data/lib/terminitor/dsl.rb +81 -0
- data/lib/terminitor/runner.rb +76 -40
- data/lib/terminitor/version.rb +1 -1
- data/lib/terminitor/yaml.rb +20 -0
- data/templates/example.yml.tt +16 -0
- data/terminitor.gemspec +11 -4
- data/test.watchr +70 -0
- data/test/abstract_core_test.rb +79 -0
- data/test/cli_test.rb +121 -0
- data/test/cores/konsole_core_test.rb +56 -0
- data/test/cores/mac_core_test.rb +84 -0
- data/test/dsl_test.rb +15 -0
- data/test/fixtures/bar.term +16 -0
- data/test/fixtures/foo.term +21 -0
- data/test/fixtures/foo.yml +1 -0
- data/test/runner_test.rb +234 -0
- data/test/teststrap.rb +6 -37
- data/test/yaml_test.rb +13 -0
- metadata +49 -17
- data/test/terminitor_test.rb +0 -152
@@ -0,0 +1,54 @@
|
|
1
|
+
module Terminitor
|
2
|
+
# KDE Konsole Core for Terminitor
|
3
|
+
# This Core manages all the interaction with Konsole's dbus interface
|
4
|
+
class KonsoleCore < AbstractCore
|
5
|
+
def initialize(path)
|
6
|
+
super
|
7
|
+
bus = DBus::SessionBus.instance
|
8
|
+
@konsole_service = bus.service("org.kde.konsole")
|
9
|
+
@konsole = get_konsole
|
10
|
+
end
|
11
|
+
|
12
|
+
# Executes the Command
|
13
|
+
# execute_command 'cd /path/to', {}
|
14
|
+
def execute_command(cmd, options = {})
|
15
|
+
# add carriange return if missing, otherwise the command won't be executed
|
16
|
+
cmd += "\n" if (cmd =~ /\n\Z/).nil?
|
17
|
+
options[:in].sendText(cmd)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Opens a new tab and returns itself.
|
21
|
+
def open_tab
|
22
|
+
session_number = @konsole.newSession
|
23
|
+
session_object = @konsole_service.object("/Sessions/#{session_number}")
|
24
|
+
session_object.introspect
|
25
|
+
session_object["org.kde.konsole.Session"]
|
26
|
+
end
|
27
|
+
|
28
|
+
# Opens a new window and returns the tab object.
|
29
|
+
def open_window
|
30
|
+
session_number = @konsole.currentSession
|
31
|
+
session_object = @konsole_service.object("/Sessions/#{session_number}")
|
32
|
+
session_object.introspect
|
33
|
+
session_object["org.kde.konsole.Session"]
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def get_konsole
|
39
|
+
begin
|
40
|
+
konsole_object = @konsole_service.object("/Konsole")
|
41
|
+
konsole_object.introspect
|
42
|
+
return konsole_object["org.kde.konsole.Konsole"]
|
43
|
+
rescue DBus::Error => e
|
44
|
+
if e.dbus_message.error_name =="org.freedesktop.DBus.Error.ServiceUnknown"
|
45
|
+
system "konsole"
|
46
|
+
sleep(2)
|
47
|
+
retry
|
48
|
+
else
|
49
|
+
raise e
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Terminitor
|
2
|
+
# Mac OS X Core for Terminitor
|
3
|
+
# This Core manages all the interaction with Appscript and the Terminal
|
4
|
+
class MacCore < AbstractCore
|
5
|
+
include Appscript
|
6
|
+
|
7
|
+
# Initialize @terminal with Terminal.app, Load the Windows, store the Termfile
|
8
|
+
# Terminitor::MacCore.new('/path')
|
9
|
+
def initialize(path)
|
10
|
+
super
|
11
|
+
@terminal = app('Terminal')
|
12
|
+
@windows = @terminal.windows
|
13
|
+
end
|
14
|
+
|
15
|
+
# executes the given command via appscript
|
16
|
+
# execute_command 'cd /path/to', :in => #<tab>
|
17
|
+
def execute_command(cmd, options = {})
|
18
|
+
active_window.do_script(cmd, options)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Opens a new tab and returns itself.
|
22
|
+
def open_tab
|
23
|
+
super
|
24
|
+
terminal_process.keystroke("t", :using => :command_down)
|
25
|
+
return_last_tab
|
26
|
+
end
|
27
|
+
|
28
|
+
# Opens A New Window and returns the tab object.
|
29
|
+
def open_window
|
30
|
+
terminal_process.keystroke("n", :using => :command_down)
|
31
|
+
return_last_tab
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns the Terminal Process
|
35
|
+
# We need this method to workaround appscript so that we can instantiate new tabs and windows.
|
36
|
+
# otherwise it would have looked something like window.make(:new => :tab) but that doesn't work.
|
37
|
+
def terminal_process
|
38
|
+
app("System Events").application_processes["Terminal.app"]
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns the last instantiated tab from active window
|
42
|
+
def return_last_tab
|
43
|
+
local_window = active_window
|
44
|
+
local_tabs = local_window.tabs if local_window
|
45
|
+
local_tabs.last.get if local_tabs
|
46
|
+
end
|
47
|
+
|
48
|
+
# returns the active window by checking if its the :frontmost
|
49
|
+
def active_window
|
50
|
+
windows = @terminal.windows.get
|
51
|
+
windows.detect do |window|
|
52
|
+
window.properties_.get[:frontmost] rescue false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
# These methods are here for reference so I can ponder later
|
59
|
+
# how I could possibly use them.
|
60
|
+
# And Currently aren't tested. =(
|
61
|
+
|
62
|
+
# returns a window by the id
|
63
|
+
def window_by_id(id)
|
64
|
+
@windows.ID(id)
|
65
|
+
end
|
66
|
+
|
67
|
+
# grabs the window id.
|
68
|
+
def window_id(window)
|
69
|
+
window.id_.get
|
70
|
+
end
|
71
|
+
|
72
|
+
# set_window_title #<Window>, "hi"
|
73
|
+
# Note: This sets all the windows to the same title.
|
74
|
+
def set_window_title(window, title)
|
75
|
+
window.custom_title.set(title)
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Terminitor
|
2
|
+
# This class parses the Termfile to fit the new Ruby Dsl Syntax
|
3
|
+
class Dsl
|
4
|
+
|
5
|
+
def initialize(path)
|
6
|
+
file = File.read(path)
|
7
|
+
@setup = []
|
8
|
+
@windows = { 'default' => {}}
|
9
|
+
@_context = @windows['default']
|
10
|
+
instance_eval(file)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Contains all commands that will be run prior to the usual 'workflow'
|
14
|
+
# e.g bundle install, setup forks, etc ...
|
15
|
+
# setup "bundle install", "brew update"
|
16
|
+
# setup { run('bundle install') }
|
17
|
+
def setup(*commands, &block)
|
18
|
+
setup_tasks = @setup
|
19
|
+
if block_given?
|
20
|
+
@_context, @_old_context = setup_tasks, @_context
|
21
|
+
instance_eval(&block)
|
22
|
+
@_context = @_old_context
|
23
|
+
else
|
24
|
+
setup_tasks.concat(commands)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# sets command context to be run inside a specific window
|
29
|
+
# window('new window') { tab('ls','gitx') }
|
30
|
+
def window(name = nil, &block)
|
31
|
+
window_tabs = @windows[name || "window#{@windows.keys.size}"] = {}
|
32
|
+
@_context, @_old_context = window_tabs, @_context
|
33
|
+
instance_eval(&block)
|
34
|
+
@_context = @_old_context
|
35
|
+
end
|
36
|
+
|
37
|
+
# stores command in context
|
38
|
+
# run 'brew update'
|
39
|
+
def run(command)
|
40
|
+
@_context << command
|
41
|
+
end
|
42
|
+
|
43
|
+
# sets command context to be run inside specific tab
|
44
|
+
# tab('new tab') { run 'mate .' }
|
45
|
+
# tab 'ls', 'gitx'
|
46
|
+
def tab(name= nil, *commands, &block)
|
47
|
+
if block_given?
|
48
|
+
tab_tasks = @_context[name || "tab#{@_context.keys.size}"] = []
|
49
|
+
@_context, @_old_context = tab_tasks, @_context
|
50
|
+
instance_eval(&block)
|
51
|
+
@_context = @_old_context
|
52
|
+
else
|
53
|
+
tab_tasks = @_context["tab#{@_context.keys.size}"] = []
|
54
|
+
tab_tasks.concat([name] + commands)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns yaml file as Terminitor formmatted hash
|
59
|
+
def to_hash
|
60
|
+
{ :setup => @setup, :windows => @windows }
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
#
|
67
|
+
# in_context @setup, commands, &block
|
68
|
+
# in_context @tabs["name"], commands, &block
|
69
|
+
def in_context(tasks_instance,*commands, &block)
|
70
|
+
if block_given?
|
71
|
+
@_context, @_old_context = instance_variable_get(name), @_context
|
72
|
+
instance_eval(&block)
|
73
|
+
@_context = @_old_context
|
74
|
+
else
|
75
|
+
@setup << commands
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
data/lib/terminitor/runner.rb
CHANGED
@@ -1,67 +1,103 @@
|
|
1
1
|
module Terminitor
|
2
|
+
# This module contains all the helper methods for the Cli component.
|
2
3
|
module Runner
|
3
4
|
|
5
|
+
# Finds the appropriate platform core, else say you don't got it.
|
6
|
+
# find_core RUBY_PLATFORM
|
7
|
+
def find_core(platform)
|
8
|
+
core = case platform.downcase
|
9
|
+
when %r{darwin} then Terminitor::MacCore
|
10
|
+
when %r{linux} then Terminitor::KonsoleCore # TODO check for gnome and others
|
11
|
+
else nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Execute the core with the given method.
|
16
|
+
# execute_core :process!, 'project'
|
17
|
+
# execute_core :setup!, 'my_project'
|
18
|
+
def execute_core(method, project)
|
19
|
+
if path = resolve_path(project)
|
20
|
+
core = find_core(RUBY_PLATFORM)
|
21
|
+
core ? core.new(path).send(method) : say("No suitable core found!")
|
22
|
+
else
|
23
|
+
return_error_message(project)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
4
27
|
# opens doc in system designated editor
|
28
|
+
# open_in_editor '/path/to', 'nano'
|
5
29
|
def open_in_editor(path, editor=nil)
|
6
30
|
editor = editor || ENV['TERM_EDITOR'] || ENV['EDITOR']
|
7
31
|
say "please set $EDITOR or $TERM_EDITOR in your .bash_profile." unless editor
|
8
32
|
system("#{editor || 'open'} #{path}")
|
9
33
|
end
|
10
34
|
|
11
|
-
|
12
|
-
|
13
|
-
|
35
|
+
# returns path to file
|
36
|
+
# resolve_path 'my_project'
|
37
|
+
def resolve_path(project)
|
38
|
+
unless project.empty?
|
39
|
+
path = config_path(project, :yml) # Give old yml path
|
40
|
+
return path if File.exists?(path)
|
41
|
+
path = config_path(project, :term) # Give new term path.
|
42
|
+
return path if File.exists?(path)
|
43
|
+
nil
|
44
|
+
else
|
45
|
+
path = File.join(options[:root],"Termfile")
|
46
|
+
return path if File.exists?(path)
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
end
|
14
50
|
|
15
|
-
|
16
|
-
|
17
|
-
|
51
|
+
# returns first line of file
|
52
|
+
# grab_comment_for_file '/path/to'
|
53
|
+
def grab_comment_for_file(file)
|
54
|
+
first_line = File.readlines(file).first
|
55
|
+
first_line =~ /^\s*?#/ ? ("-" + first_line.gsub("#","")) : "\n"
|
56
|
+
end
|
18
57
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
58
|
+
# Return file in config_path
|
59
|
+
# config_path '/path/to', :term
|
60
|
+
def config_path(file, type = :yml)
|
61
|
+
return File.join(options[:root],"Termfile") if file.empty?
|
62
|
+
dir = File.join(ENV['HOME'],'.terminitor')
|
63
|
+
if type == :yml
|
64
|
+
File.join(dir, "#{file.sub(/\.yml$/, '')}.yml")
|
65
|
+
else
|
66
|
+
File.join(dir, "#{file.sub(/\.term$/, '')}.term")
|
25
67
|
end
|
26
68
|
end
|
27
69
|
|
28
|
-
|
70
|
+
# Returns error message depending if project is specified
|
71
|
+
# return_error_message 'hi
|
72
|
+
def return_error_message(project)
|
29
73
|
unless project.empty?
|
30
|
-
|
74
|
+
say "'#{project}' doesn't exist! Please run 'terminitor open #{project.gsub(/\..*/,'')}'"
|
31
75
|
else
|
32
|
-
|
76
|
+
say "Termfile doesn't exist! Please run 'terminitor open' in project directory"
|
33
77
|
end
|
34
78
|
end
|
35
79
|
|
36
|
-
|
37
|
-
|
80
|
+
# This will clone a repo in the current directory.
|
81
|
+
# It will first try to clone via ssh(read/write),
|
82
|
+
# if not fall back to git-read only, else, fail.
|
83
|
+
def clone_repo(username, project)
|
84
|
+
github = `which github`
|
85
|
+
return false if github.empty?
|
86
|
+
command = "github clone #{username} #{project}"
|
87
|
+
system(command + " --ssh") || system(command)
|
38
88
|
end
|
39
89
|
|
40
|
-
#
|
41
|
-
#
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
if @got_first_tab_already
|
50
|
-
app("System Events").application_processes["Terminal.app"].keystroke("t", :using => :command_down)
|
90
|
+
# Fetch the git repo and run the setup block
|
91
|
+
# fetch_repo 'achiu', 'terminitor', :setup => true
|
92
|
+
def fetch_repo(username, project, options ={})
|
93
|
+
if clone_repo(username, project)
|
94
|
+
path = File.join(Dir.pwd, project)
|
95
|
+
FileUtils.cd(path)
|
96
|
+
invoke(:setup, []) if options[:setup]
|
97
|
+
else
|
98
|
+
say("could not fetch repo!")
|
51
99
|
end
|
52
|
-
@got_first_tab_already = true
|
53
|
-
local_window = active_window(terminal)
|
54
|
-
@working_dir = Dir.pwd
|
55
|
-
local_tabs = local_window.tabs if local_window
|
56
|
-
local_tabs.last.get if local_tabs
|
57
100
|
end
|
58
101
|
|
59
|
-
# makes sure to set active window as frontmost.
|
60
|
-
def active_window(terminal)
|
61
|
-
(1..terminal.windows.count).each do |i|
|
62
|
-
window = terminal.windows[i]
|
63
|
-
return window if window.properties_.get[:frontmost]
|
64
|
-
end
|
65
|
-
end
|
66
102
|
end
|
67
103
|
end
|
data/lib/terminitor/version.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Terminitor
|
4
|
+
# This class holds the legacy YAML sytnax for Terminitor
|
5
|
+
class Yaml
|
6
|
+
attr_accessor :file
|
7
|
+
|
8
|
+
# Load in the Yaml file...
|
9
|
+
def initialize(path)
|
10
|
+
@file = YAML.load File.read(path)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns yaml file as Terminitor formmatted hash
|
14
|
+
def to_hash
|
15
|
+
combined = @file.inject({}) {|base, item| base.merge!(item) ; base } # merge the array of hashes.
|
16
|
+
{ :setup => nil, :windows => { 'default' => combined } }
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# COMMENT OF SCRIPT HERE
|
2
|
+
# you can make as many tabs as you wish...
|
3
|
+
# tab names are actually arbitrary at this point too.
|
4
|
+
---
|
5
|
+
- tab1:
|
6
|
+
- cd ~/foo/bar
|
7
|
+
- gitx
|
8
|
+
- tab2:
|
9
|
+
- mysql -u root
|
10
|
+
- use test;
|
11
|
+
- show tables;
|
12
|
+
- tab3: echo "hello world"
|
13
|
+
- tab4: cd ~/baz/ && git pull
|
14
|
+
- tab5:
|
15
|
+
- cd ~/foo/project
|
16
|
+
- autotest
|
data/terminitor.gemspec
CHANGED
@@ -13,17 +13,24 @@ Gem::Specification.new do |s|
|
|
13
13
|
|
14
14
|
s.required_rubygems_version = ">= 1.3.6"
|
15
15
|
s.rubyforge_project = "terminitor"
|
16
|
-
|
17
|
-
|
16
|
+
|
17
|
+
# Platform Specific Dependencies
|
18
|
+
case RUBY_PLATFORM.downcase
|
19
|
+
when %r{darwin}
|
20
|
+
s.add_dependency "rb-appscript"
|
21
|
+
else
|
22
|
+
end
|
23
|
+
|
18
24
|
s.add_dependency "thor", "~>0.14.0"
|
25
|
+
s.add_dependency "github"
|
19
26
|
s.add_development_dependency "bundler", "~>1.0.0"
|
20
|
-
s.add_development_dependency "riot", "~>0.
|
27
|
+
s.add_development_dependency "riot", "~>0.11.0"
|
21
28
|
s.add_development_dependency "rr"
|
22
29
|
s.add_development_dependency "fakefs"
|
23
30
|
s.post_install_message = %q{********************************************************************************
|
24
31
|
|
25
32
|
Terminitor is installed!
|
26
|
-
Please run 'terminitor
|
33
|
+
Please run 'terminitor init'.
|
27
34
|
This will create a directory at ~/.terminitor which will hold all your global scripts.
|
28
35
|
Thanks!
|
29
36
|
|
data/test.watchr
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
ENV["WATCHR"] = "1"
|
2
|
+
system 'clear'
|
3
|
+
|
4
|
+
def growl(message)
|
5
|
+
growlnotify = `which growlnotify`.chomp
|
6
|
+
title = "Watchr Test Results"
|
7
|
+
image = message.include?('0 failures, 0 errors') ? "~/.watchr_images/passed.png" : "~/.watchr_images/failed.png"
|
8
|
+
options = "-w -n Watchr --image '#{File.expand_path(image)}' -m '#{message}' '#{title}'"
|
9
|
+
system %(#{growlnotify} #{options} &)
|
10
|
+
end
|
11
|
+
|
12
|
+
def run(cmd)
|
13
|
+
puts(cmd)
|
14
|
+
`#{cmd}`
|
15
|
+
end
|
16
|
+
|
17
|
+
def run_test_file(file)
|
18
|
+
system('clear')
|
19
|
+
result = run(%Q(ruby -I"lib:test" -rubygems #{file}))
|
20
|
+
growl result.split("\n").last rescue nil
|
21
|
+
puts result
|
22
|
+
end
|
23
|
+
|
24
|
+
def run_all_tests
|
25
|
+
system('clear')
|
26
|
+
result = run "rake test"
|
27
|
+
growl result.split("\n").last rescue nil
|
28
|
+
puts result
|
29
|
+
end
|
30
|
+
|
31
|
+
def run_all_features
|
32
|
+
system('clear')
|
33
|
+
run "cucumber"
|
34
|
+
end
|
35
|
+
|
36
|
+
def related_test_files(path)
|
37
|
+
Dir['test/**/*.rb'].select { |file| file =~ /#{File.basename(path).split(".").first}_test.rb/ }
|
38
|
+
end
|
39
|
+
|
40
|
+
def run_suite
|
41
|
+
run_all_tests
|
42
|
+
# run_all_features
|
43
|
+
end
|
44
|
+
|
45
|
+
watch('test/teststrap\.rb') { run_all_tests }
|
46
|
+
watch('test/(.*).*_test\.rb') { |m| run_test_file(m[0]) }
|
47
|
+
watch('lib/.*/.*\.rb') { |m| related_test_files(m[0]).map {|tf| run_test_file(tf) } }
|
48
|
+
# watch('features/.*/.*\.feature') { run_all_features }
|
49
|
+
|
50
|
+
# Ctrl-\
|
51
|
+
Signal.trap 'QUIT' do
|
52
|
+
puts " --- Running all tests ---\n\n"
|
53
|
+
run_all_tests
|
54
|
+
end
|
55
|
+
|
56
|
+
@interrupted = false
|
57
|
+
|
58
|
+
# Ctrl-C
|
59
|
+
Signal.trap 'INT' do
|
60
|
+
if @interrupted then
|
61
|
+
@wants_to_quit = true
|
62
|
+
abort("\n")
|
63
|
+
else
|
64
|
+
puts "Interrupt a second time to quit"
|
65
|
+
@interrupted = true
|
66
|
+
Kernel.sleep 1.5
|
67
|
+
# raise Interrupt, nil # let the run loop catch it
|
68
|
+
run_suite
|
69
|
+
end
|
70
|
+
end
|