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.
@@ -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