automux 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/.gitignore +5 -0
  2. data/Gemfile +6 -0
  3. data/Gemfile.lock +20 -0
  4. data/LICENSE.txt +22 -0
  5. data/VERSION +1 -0
  6. data/automux.gemspec +18 -0
  7. data/bin/automux +22 -0
  8. data/data/automux/blueprints/default.yml +26 -0
  9. data/data/automux/recipes/default.sh.erb +46 -0
  10. data/features/custom_recipes.feature +63 -0
  11. data/features/error_messages.feature +8 -0
  12. data/features/general_usage.feature +180 -0
  13. data/features/managing_blueprints.feature +66 -0
  14. data/features/runtime_options.feature +84 -0
  15. data/features/session_and_window_options.feature +67 -0
  16. data/features/session_hooks.feature +68 -0
  17. data/features/setup_windows.feature +22 -0
  18. data/features/step_definitions/custom_recipes_steps.rb +9 -0
  19. data/features/step_definitions/managing_blueprints_steps.rb +9 -0
  20. data/features/step_definitions/setup_windows_steps.rb +18 -0
  21. data/features/step_definitions/shared_steps.rb +43 -0
  22. data/features/support/env.rb +8 -0
  23. data/features/support/hooks.rb +4 -0
  24. data/features/support/transformations.rb +6 -0
  25. data/lib/automux.rb +9 -0
  26. data/lib/automux/cache.rb +10 -0
  27. data/lib/automux/cache/blueprint.rb +20 -0
  28. data/lib/automux/cache/recipe.rb +27 -0
  29. data/lib/automux/controller.rb +14 -0
  30. data/lib/automux/controller/base.rb +18 -0
  31. data/lib/automux/controller/blueprints.rb +45 -0
  32. data/lib/automux/controller/messages.rb +11 -0
  33. data/lib/automux/controller/recipes.rb +39 -0
  34. data/lib/automux/controller/setup.rb +11 -0
  35. data/lib/automux/controller/support.rb +5 -0
  36. data/lib/automux/controller/support/filters.rb +55 -0
  37. data/lib/automux/controller/support/rendering.rb +54 -0
  38. data/lib/automux/core.rb +11 -0
  39. data/lib/automux/core/base.rb +7 -0
  40. data/lib/automux/core/blueprint.rb +31 -0
  41. data/lib/automux/core/error.rb +15 -0
  42. data/lib/automux/core/hook.rb +26 -0
  43. data/lib/automux/core/option.rb +20 -0
  44. data/lib/automux/core/recipe.rb +12 -0
  45. data/lib/automux/core/support.rb +6 -0
  46. data/lib/automux/core/support/custom_accessors.rb +15 -0
  47. data/lib/automux/core/support/hooks_helper.rb +28 -0
  48. data/lib/automux/core/support/options_helper.rb +18 -0
  49. data/lib/automux/core/tmux.rb +6 -0
  50. data/lib/automux/core/tmux/pane.rb +19 -0
  51. data/lib/automux/core/tmux/session.rb +137 -0
  52. data/lib/automux/core/tmux/window.rb +76 -0
  53. data/lib/automux/initializers.rb +2 -0
  54. data/lib/automux/initializers/custom_hooks.rb +4 -0
  55. data/lib/automux/initializers/setup_caches.rb +3 -0
  56. data/lib/automux/library.rb +5 -0
  57. data/lib/automux/library/mini_erb.rb +22 -0
  58. data/lib/automux/library/yaml_parser.rb +41 -0
  59. data/lib/automux/paths.rb +41 -0
  60. data/lib/automux/setup.rb +0 -0
  61. data/lib/automux/views/blueprints/copy.sh.erb +2 -0
  62. data/lib/automux/views/blueprints/create.sh.erb +2 -0
  63. data/lib/automux/views/blueprints/edit.sh.erb +1 -0
  64. data/lib/automux/views/messages/error.sh.erb +3 -0
  65. data/lib/automux/views/setup/clone_defaults.sh.erb +21 -0
  66. data/test/session_test.rb +16 -0
  67. data/test/support/common_methods.rb +0 -0
  68. data/test/support/factories.rb +13 -0
  69. data/test/support/hash_factory.rb +19 -0
  70. data/test/support/test_helper.rb +7 -0
  71. metadata +136 -0
@@ -0,0 +1,45 @@
1
+ module Automux
2
+ module Controller
3
+ class Blueprints < Base
4
+ before_filter :load_blueprint, only: [:edit, :copy, :cp, :delete, :rm]
5
+
6
+ # blueprint_name.yml will be searched under $HOME/.automux/blueprints
7
+ # $ automux blueprint edit blueprint_name
8
+ def edit
9
+ @binding = @blueprint.get_binding
10
+ render 'edit'
11
+ end
12
+
13
+ # This copies the content from default.yml and opens the new file using $EDITOR
14
+ # $ automux blueprint create new_blueprint_name
15
+ def create
16
+ blueprint = Automux::Core::Blueprint.build_by_name(params[:name])
17
+ blueprint.source = Automux::Cache::Blueprint.find_by_name('default')
18
+ @binding = blueprint.get_binding
19
+ render 'create'
20
+ end
21
+
22
+ # $ automux blueprint copy source destination
23
+ def copy
24
+ clone_blueprint = Automux::Core::Blueprint.build_by_name(params[:clone_name])
25
+ clone_blueprint.source = @blueprint
26
+ @binding = clone_blueprint.get_binding
27
+ render 'copy'
28
+ end
29
+ alias_method :cp, :copy
30
+
31
+ # $ automux blueprint delete some_blueprint
32
+ def delete
33
+ @binding = @blueprint.get_binding
34
+ render 'delete'
35
+ end
36
+ alias_method :rm, :delete
37
+
38
+ private ###
39
+
40
+ def load_blueprint
41
+ @blueprint = Automux::Cache::Blueprint.find_by_name(params[:name])
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,11 @@
1
+ module Automux
2
+ module Controller
3
+ class Messages < Base
4
+ def error
5
+ error = Automux::Core::Error.new(params[:message])
6
+ @binding = error.get_binding
7
+ render 'error'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,39 @@
1
+ module Automux
2
+ module Controller
3
+ class Recipes < Base
4
+ before_filter :load_recipe, only: :automate
5
+ before_filter :load_blueprint, only: :automate
6
+ before_filter :check_blueprint, only: :automate
7
+ before_filter :check_recipe, only: :automate
8
+ before_filter :load_and_setup_session, only: :automate
9
+
10
+ def automate
11
+ @binding = @session.get_binding
12
+ render @recipe.path
13
+ end
14
+
15
+ private ###
16
+
17
+ def load_recipe
18
+ @recipe = Automux::Cache::Recipe.find_by_name(params[:recipe_name])
19
+ end
20
+
21
+ def load_blueprint
22
+ @blueprint = Automux::Cache::Blueprint.find_by_name(params[:blueprint_name])
23
+ end
24
+
25
+ def check_blueprint
26
+ notify_error "Unable to find blueprint named #{ params[:blueprint_name] }.yml" if @blueprint.nil?
27
+ end
28
+
29
+ def check_recipe
30
+ notify_error "Unable to find recipe named #{ params[:recipe_name] }.sh.erb" if @recipe.nil?
31
+ end
32
+
33
+ def load_and_setup_session
34
+ @session = Automux::Core::Tmux::Session.new(@blueprint.read)
35
+ @session.setup
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,11 @@
1
+ module Automux
2
+ module Controller
3
+ class Setup < Base
4
+
5
+ def clone_defaults
6
+ @binding = binding
7
+ render 'clone_defaults'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ require 'automux/controller/support/filters'
2
+ require 'automux/controller/support/rendering'
3
+
4
+ module Automux::Controller::Support
5
+ end
@@ -0,0 +1,55 @@
1
+ module Automux
2
+ module Controller
3
+ module Support
4
+ module Filters
5
+ attr_reader :filters
6
+ private :filters
7
+
8
+ # Filters is included in the Base controller and all the following methods are intended for its subclasses.
9
+ def inherited(base)
10
+ base.instance_variable_set '@filters', {}
11
+ end
12
+
13
+ # before_filter does not define its logic right away.
14
+ def before_filter(filter_name, options)
15
+ [options[:only]].flatten.each do |action|
16
+ add_filter(filter_name, action)
17
+ end
18
+ end
19
+
20
+ # This is a custom hook intended to run after the subclass definition is read.
21
+ # This helps in calling the before_filter at the top but defining its logic later.
22
+ # See: automux/initializers/custom_hooks.rb for invocation.
23
+ def after_inherited(base)
24
+ # E.g. filters = { automate: [:load_recipe, :load_session], edit: [:load_recipe] }
25
+ base.class_eval do
26
+ # |automate, [:load_recipe, :load_session]|
27
+ filters.each_pair do |name, filter_list|
28
+
29
+ # def automate_with_filters
30
+ # load_recipe
31
+ # load_session
32
+ # automate_without_filters
33
+ # end
34
+ define_method "#{ name }_with_filters" do
35
+ filter_list.each { |filter_name| send(filter_name) }
36
+ send("#{ name }_without_filters")
37
+ end
38
+
39
+ # alias_method_chain automate, filters
40
+ alias_method "#{ name }_without_filters", name
41
+ alias_method name, "#{ name }_with_filters"
42
+ end
43
+ end
44
+ end
45
+
46
+ private ###
47
+
48
+ def add_filter(filter_name, action)
49
+ filters[action] ||= []
50
+ filters[action] << filter_name
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,54 @@
1
+ module Automux
2
+ module Controller
3
+ module Support
4
+ module Rendering
5
+
6
+ # There are two requirements to render a file.
7
+ # 1. @binding
8
+ # 2. file_name
9
+ def render(view)
10
+ path =
11
+ # If the full path to the file is given, use that instead.
12
+ if FileTest.exists?(view)
13
+ view
14
+ else
15
+ deduce_full_path(view)
16
+ end
17
+
18
+ execute Automux::Library::MiniErb.new(File.read(path)).result(@binding)
19
+ end
20
+
21
+ private ###
22
+
23
+ # The full file path will be deduced using current controller name.
24
+ # So for Blueprints, the file will be searched under $HOME/.automux/blueprints.
25
+ # The file will be a bash script with erb support. Hence the need of a @binding object.
26
+ def deduce_full_path(view)
27
+ views_folder_name = demodulize(self.class.name).downcase
28
+ File.join(Paths.root, Paths.views, views_folder_name, "#{ view }.sh.erb")
29
+ end
30
+
31
+ def execute(result)
32
+ modified_result = remove_empty_lines(result)
33
+
34
+ if ENV['AUTOMUX_ENV'] == 'test'
35
+ File.open('/tmp/results', 'w') { |f| f.write(modified_result) }
36
+ exit
37
+ else
38
+ exec(modified_result)
39
+ end
40
+ end
41
+
42
+ # The recipe files can have empty lines for clarity. Remove them here.
43
+ def remove_empty_lines(string)
44
+ string.split("\n").reject { |text| text.strip.empty? }.join("\n")
45
+ end
46
+
47
+ # Remove all parent namespacing.
48
+ def demodulize(class_name)
49
+ class_name.split('::').last
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,11 @@
1
+ require 'automux/core/support'
2
+ require 'automux/core/base'
3
+ require 'automux/core/hook'
4
+ require 'automux/core/option'
5
+ require 'automux/core/tmux'
6
+ require 'automux/core/recipe'
7
+ require 'automux/core/blueprint'
8
+ require 'automux/core/error'
9
+
10
+ module Automux::Core
11
+ end
@@ -0,0 +1,7 @@
1
+ module Automux
2
+ module Core
3
+ class Base
4
+ extend Automux::Core::Support::CustomAccessors
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,31 @@
1
+ module Automux
2
+ module Core
3
+ class Blueprint < Base
4
+ attr_reader :name, :path, :source_blueprint
5
+
6
+ def initialize(path)
7
+ @name = File.basename(path, '.yml')
8
+ @path = path
9
+ end
10
+
11
+ def read
12
+ Automux::Library::YamlParser.load_file(path)
13
+ end
14
+
15
+ def get_binding
16
+ binding
17
+ end
18
+
19
+ def source=(blueprint)
20
+ @source_blueprint = blueprint
21
+ end
22
+
23
+ class << self
24
+ def build_by_name(name)
25
+ path = File.join(Automux::Paths.blueprints_container, "#{ name }.yml")
26
+ new(path)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,15 @@
1
+ module Automux
2
+ module Core
3
+ class Error
4
+ attr_reader :message
5
+
6
+ def initialize(message)
7
+ @message = message
8
+ end
9
+
10
+ def get_binding
11
+ binding
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ require 'erb'
2
+
3
+ module Automux
4
+ module Core
5
+ class Hook
6
+ PRE = 2
7
+ POST = 4
8
+
9
+ attr_reader :command, :type
10
+ private :type
11
+
12
+ def initialize(target, type, command)
13
+ @type = self.class.const_get(type.upcase)
14
+ @command = ERB.new(command).result(target.get_binding)
15
+ end
16
+
17
+ def pre?
18
+ type == PRE
19
+ end
20
+
21
+ def post?
22
+ type == POST
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,20 @@
1
+ module Automux
2
+ module Core
3
+ class Option
4
+ attr_reader :name, :value
5
+
6
+ BOOLEAN_DICTIONARY = { 'true' => :on, 'false' => :off }
7
+
8
+ def initialize(name, value)
9
+ @name = name
10
+ @value = translate_booleans(value)
11
+ end
12
+
13
+ private ###
14
+
15
+ def translate_booleans(value)
16
+ value.to_s.gsub(/(true|false)/, BOOLEAN_DICTIONARY)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ module Automux
2
+ module Core
3
+ class Recipe < Base
4
+ attr_reader :name, :path
5
+
6
+ def initialize(path)
7
+ @name = File.basename(path, '.sh.erb')
8
+ @path = path
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,6 @@
1
+ require 'automux/core/support/custom_accessors'
2
+ require 'automux/core/support/hooks_helper'
3
+ require 'automux/core/support/options_helper'
4
+
5
+ module Automux::Core::Support
6
+ end
@@ -0,0 +1,15 @@
1
+ module Automux
2
+ module Core
3
+ module Support
4
+ module CustomAccessors
5
+ def dup_attr_reader(*names)
6
+ names.each do |name|
7
+ define_method name do
8
+ instance_variable_get("@#{ name }").dup
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,28 @@
1
+ module Automux
2
+ module Core
3
+ module Support
4
+ module HooksHelper
5
+ attr_reader :data_hooks
6
+ private :data_hooks
7
+
8
+ def pre_hooks
9
+ hooks.select(&:pre?)
10
+ end
11
+
12
+ def post_hooks
13
+ hooks.select(&:post?)
14
+ end
15
+
16
+ private ###
17
+
18
+ def setup_hooks
19
+ data_hooks.each do |type, commands|
20
+ [commands].flatten.each do |command|
21
+ @hooks << Hook.new(self, type, command)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,18 @@
1
+ module Automux
2
+ module Core
3
+ module Support
4
+ module OptionsHelper
5
+ attr_reader :data_options
6
+ private :data_options
7
+
8
+ private ###
9
+
10
+ def setup_options
11
+ data_options.each do |name, value|
12
+ @options << Automux::Core::Option.new(name, value)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,6 @@
1
+ require 'automux/core/tmux/session'
2
+ require 'automux/core/tmux/window'
3
+ require 'automux/core/tmux/pane'
4
+
5
+ module Automux::Core::Tmux
6
+ end