terminitor 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
- def do_project(path)
12
- terminal = app('Terminal')
13
- tabs = load_config(path)
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
- tabs.each do |hash|
16
- tabname = hash.keys.first
17
- cmds = hash.values.first
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
- tab = self.open_tab(terminal)
20
- cmds = [cmds].flatten
21
- cmds.insert(0, "cd \"#{@working_dir}\" ; clear") unless @working_dir.to_s.empty?
22
- cmds.each do |cmd|
23
- terminal.windows.last.do_script(cmd, :in => tab)
24
- end
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
- def resolve_path(project)
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
- File.join(ENV['HOME'],'.terminitor', "#{project.sub(/\.yml$/, '')}.yml")
74
+ say "'#{project}' doesn't exist! Please run 'terminitor open #{project.gsub(/\..*/,'')}'"
31
75
  else
32
- File.join(options[:root],"Termfile")
76
+ say "Termfile doesn't exist! Please run 'terminitor open' in project directory"
33
77
  end
34
78
  end
35
79
 
36
- def load_config(path)
37
- YAML.load(File.read(path))
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
- # somewhat hacky in that it requires Terminal to exist,
41
- # which it would if we run this script from a Terminal,
42
- # but it won't work if called e.g. from cron.
43
- # The latter case would just require us to open a Terminal
44
- # using do_script() first with no :in target.
45
- #
46
- # One more hack: if we're getting the first tab, we return
47
- # the term window's only current tab, else we send a CMD+T
48
- def open_tab(terminal)
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
@@ -1,3 +1,3 @@
1
1
  module Terminitor
2
- VERSION = "0.0.5"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -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
- s.add_dependency "rb-appscript"
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.14.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 setup'.
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