org-converge 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ rvm:
2
+ - 1.9.3
3
+ - 2.0.0
4
+ notifications:
5
+ disabled: true
data/README.md ADDED
@@ -0,0 +1,130 @@
1
+ Org Converge
2
+ ------------
3
+ [![Build Status](https://travis-ci.org/wallyqs/org-converge.svg?branch=master)](https://travis-ci.org/wallyqs/org-converge)
4
+
5
+ # Description
6
+
7
+ A tool which uses Org mode syntax to describe, configure and
8
+ setup something, borrowing some ideas of what is possible to
9
+ do with tools like `chef-solo`, `puppet`, `ansible`, etc...
10
+
11
+ Can also be used for tangling code blocks like Org Babel does.
12
+
13
+ # Installing
14
+
15
+ $ gem install org-converge
16
+
17
+ # Motivation
18
+
19
+ The Org babel syntax has proven to be flexible enough to produce
20
+ *reproducible research* papers. Then, I believe that configuring and setting up
21
+ a server for example is something that could be also be done using
22
+ the same syntax, given that *converging* the configuration is something
23
+ that one ought to be able to reproduce.
24
+
25
+ # Example usage
26
+
27
+ $ org-converge spec/converge_examples/basic_tangle/setup.org --showfiles
28
+
29
+ ---------- conf.yml --------------
30
+ bind: 0.0.0.0
31
+ port: 2442
32
+
33
+ mysql:
34
+ db: users
35
+ host: somewhere-example.local
36
+ password: 111111111
37
+
38
+ $ org-converge spec/converge_examples/basic_tangle/setup.org --tangle
39
+
40
+ I, [2014-03-24T00:21:08.073506 #660] INFO -- : Tangling 1 files...
41
+ I, [2014-03-24T00:21:08.073668 #660] INFO -- : BEGIN(conf.yml): Tangling 7 lines at 'conf.yml'
42
+ I, [2014-03-24T00:21:08.075562 #660] INFO -- : END(conf.yml): done.
43
+ I, [2014-03-24T00:21:08.075638 #660] INFO -- : Tangling succeeded!
44
+
45
+ # How it works
46
+
47
+ Org Converge uses an liberally extended version of Org Babel
48
+ features in order to give support for converging the configuration
49
+ of a server.
50
+
51
+ For example, using Org Babel and macros we can easily spread config
52
+ files on a server by writing the following on a `server.org` file.
53
+
54
+ ```org
55
+ #+MACRO: multitenancy_enabled true
56
+ #+MACRO: status_port true
57
+
58
+ #+begin_src yaml :tangle /etc/component.yml
59
+ multitenant: false
60
+ status_port: 10004
61
+ #+end_src
62
+ ```
63
+
64
+ And then configure it by running it as follows, (considering we have
65
+ the correct permissions):
66
+
67
+ ```sh
68
+ $ org-converge server.org
69
+ ```
70
+
71
+ This leverages on the syntax already provided by Org Babel, but one
72
+ difference here is that if we run it once again without changes...
73
+
74
+ ```sh
75
+ $ org-converge server.org
76
+ ```
77
+
78
+ ...it would finish soon since the configuration has already converged.
79
+
80
+ Next, let's say that we no only one want to set the configured templates,
81
+ but that we also want to install some packages. In that case, we
82
+ should be able to do the following:
83
+
84
+ ```org
85
+ #+macro: multitenancy_enabled true
86
+ #+macro: status_port true
87
+ #+macro: project_path path/to/project
88
+
89
+ * Configuring the component
90
+
91
+ #+begin_src yaml :tangle /etc/component.yml
92
+ multitenant: false
93
+ status_port: 10004
94
+ #+end_src
95
+
96
+ * Installing the dependencies
97
+
98
+ Need the following so that ~bundle install~ can compile
99
+ the native extensions correctly.
100
+
101
+ #+begin_src sh
102
+ apt-get install build-essentials -y
103
+ #+end_src
104
+
105
+ Then the following should work:
106
+
107
+ #+begin_src sh
108
+ cd {{{project_path}}}
109
+ bundle install
110
+ #+end_src
111
+ ```
112
+
113
+ As long as the repo has been already checked out in the directory,
114
+ the previous example will succeed.
115
+
116
+ ```sh
117
+ org-converge server.org
118
+ ```
119
+
120
+ If that is not the case, then org-converge will fail
121
+ and pickup from that last step.
122
+
123
+ More practical examples can be found in the examples directory, more will be added as
124
+ long as dogfooding from this goes well.
125
+
126
+ # Contributing
127
+
128
+ The project is in very early development at this moment, but if you
129
+ feel that it is interesting enough, please create a ticket to start
130
+ the discussion.
data/Rakefile CHANGED
@@ -8,3 +8,5 @@ RSpec::Core::RakeTask.new(:spec) do |spec|
8
8
  spec.pattern = FileList['spec/**/*_spec.rb']
9
9
  spec.rspec_opts = ['--format', 'documentation', '--colour']
10
10
  end
11
+
12
+ task :default => :spec
data/TODO CHANGED
@@ -2,21 +2,28 @@
2
2
  #+TODO: TODO | DONE CANCELED
3
3
  #+startup: showeverything
4
4
 
5
- * [0/2] 0.0.3 version
5
+ * [/] 0.0.4 version
6
6
 
7
7
  - [ ] Macros can be loaded and applied to the configuration
8
8
  - [ ] Actually support converging and idempotency
9
9
  + Do not do an operation unless it is required
10
10
  + Abort in case there was a failure in executing the script.
11
+ - [ ] Support SETUPFILE
12
+ - [ ] Heuristics for determining which binary to use for running the script
13
+ - [ ] Display how the run would look like without making changes
14
+ : org-converge setupfile.org --dry-run
15
+
16
+ * [0/3] 0.0.3 version
17
+
18
+ - [ ] Support run lists for sequential execution
11
19
 
12
- * [0/2] 0.0.2 version
20
+ * [2/2] 0.0.2 version of org-converge
13
21
 
14
22
  Run the code blocks!
15
23
 
16
- - [ ] Code blocks are executed by default after tangling
17
- Only when :shebang exists as an argument
18
- - [ ] Display how the run would look like
19
- : org-converge setupfile.org --dry-run
24
+ - [X] Code blocks are executed by default after tangling in temp dir
25
+ Only when ~:shebang~ exists as an argument
26
+ - [X] Default parallel execution of blocks
20
27
 
21
28
  * [3/3] 0.0.1 version
22
29
 
@@ -28,20 +35,7 @@ Need some basic functionality of what Org babel offers first.
28
35
  - [X] ~--tangle~ flag
29
36
  - [X] Support a root dir for when not running relative to the directory
30
37
 
31
- * [2/14] Ideas
32
- ** CANCELED We don't need to create the directories in most cases
33
-
34
- Something like this is not required because the ~:tangle~ blocks
35
- would create the necessary directories behind the scenes.
36
-
37
- #+begin_src org
38
- ,We need to prepare some directories for the configuration:
39
-
40
- ,#+begin_src converge
41
- ,mkdir -p etc/fluentd/config
42
- ,#+end_src
43
- #+end_src
44
-
38
+ * [1/18] Ideas
45
39
  ** CANCELED How to set the permissions from the directory from the file that is being tangled when it does not exists?
46
40
 
47
41
  By default, this would be 0644, but we also need to specify the
@@ -53,6 +47,22 @@ hmm dont't like this syntax for folders
53
47
 
54
48
  Let's keep it simple and just use a babel block that shells out to create the directories
55
49
  until I can think of something better.
50
+ ** TODO Clarify which ones of the header arguments to implement
51
+
52
+ http://orgmode.org/manual/Specific-header-arguments.html#Specific-header-arguments
53
+
54
+ ** TODO We don't need to create the directories in most cases (:mkdirp yes)
55
+
56
+ Something like this is not required because the ~:tangle~ blocks
57
+ would create the necessary directories behind the scenes.
58
+
59
+ #+begin_src org
60
+ ,We need to prepare some directories for the configuration:
61
+
62
+ ,#+begin_src converge
63
+ ,mkdir -p etc/fluentd/config
64
+ ,#+end_src
65
+ #+end_src
56
66
 
57
67
  ** TODO By default, it should use current dir for tangling
58
68
  ** TODO Converging: Only do an operation when it didn't finish
@@ -165,3 +175,25 @@ sudo service td-agent start
165
175
  #+begin_src sh
166
176
  sudo /etc/register-to-balancer
167
177
  #+end_src
178
+
179
+ ** TODO ~#+NAME:~ could be used in the logger for identifying the process
180
+ ** TODO Support caching?
181
+
182
+ #+begin_src emacs-lisp :cache yes :exports results
183
+ (random)
184
+ #+end_src
185
+
186
+ #+RESULTS[db54597aed193d861d01bf92110e10f28f8f40d4]:
187
+ : 842438499349743708
188
+
189
+ ** TODO Support :eval ?
190
+
191
+ #+begin_src sh :eval (print "Really doing this...")
192
+ echo "Going ahead with operation X!"
193
+ #+end_src
194
+
195
+ * Links
196
+
197
+ Super useful notes:
198
+ http://eschulte.github.io/org-scraps
199
+
data/lib/org-converge.rb CHANGED
@@ -2,6 +2,7 @@ require 'org-ruby'
2
2
  require 'org-converge/babel_output_buffer'
3
3
  require 'org-converge/babel'
4
4
  require 'org-converge/command'
5
+ require 'org-converge/engine'
5
6
  require 'org-converge/version'
6
7
 
7
8
  module Orgmode
@@ -25,9 +26,15 @@ module Orgmode
25
26
  end
26
27
 
27
28
  module StringWithColors
28
- def red; colorize("\e[0m\e[31m"); end
29
- def green; colorize("\e[0m\e[32m"); end
30
- def yellow; colorize("\e[0m\e[33m"); end
29
+ def red; colorize("\e[0m\e[31m"); end
30
+ def green; colorize("\e[0m\e[32m"); end
31
+ def yellow; colorize("\e[0m\e[33m"); end
32
+ def blue; colorize("\e[0m\e[34m"); end
33
+ def magenta; colorize("\e[0m\e[35m"); end
34
+ def cyan; colorize("\e[0m\e[36m"); end
35
+ def white; colorize("\e[0m\e[37m"); end
36
+ def bright_black; colorize("\e[0m\e[30m"); end
37
+ def bright_magenta; colorize("\e[0m\e[35m"); end
31
38
  def bold; colorize("\e[0m\e[1m"); end
32
39
  def colorize(color_code); "#{color_code}#{self}\e[0m"; end
33
40
  end
@@ -29,7 +29,9 @@ module Orgmode
29
29
 
30
30
  logger.info "BEGIN(#{tangle_file}): Tangling #{lines.count} lines at '#{file}'"
31
31
  # TODO: should abort when the directory does not exists
32
+ # Org mode blocks have :mkdirp true
32
33
  # TODO: should abort when the directory failed because of permissions
34
+ # TODO: should apply :tangle-mode for permissions
33
35
  if not Dir.exists?(File.dirname(file))
34
36
  logger.error "Could not tangle #{file} because directory does not exists!"
35
37
  raise TangleError
@@ -52,7 +54,26 @@ module Orgmode
52
54
  logger.info "END(#{file}): done."
53
55
  end
54
56
 
55
- logger.info "Tangling succeeded!".green
57
+ logger.info "Tangling succeeded!"
58
+ end
59
+
60
+ def tangle_runnable_blocks!(run_dir='run')
61
+ FileUtils.mkdir_p(run_dir)
62
+
63
+ logger.info "Tangling #{ob.scripts.count} scripts within directory: #{run_dir}..."
64
+
65
+ ob.scripts.each_pair do |script_key, script|
66
+ file = script_key.to_s
67
+ if File.exists?(file)
68
+ logger.warn "File already exists at #{file}, it will be overwritten"
69
+ end
70
+
71
+ File.open(File.join(run_dir, file), 'w') do |f|
72
+ script[:lines].each_line do |line|
73
+ f.puts line
74
+ end
75
+ end
76
+ end
56
77
  end
57
78
 
58
79
  class TangleError < Exception; end
@@ -12,12 +12,13 @@ module Orgmode
12
12
 
13
13
  # ~@scripts~ are tangled in order and ran
14
14
  # : @scripts = [text, text, ...]
15
- @scripts = []
15
+ @scripts = Hash.new {|h,k| h[k] = {:lines => '', :header => {}, :lang => ''}}
16
+ @scripts_counter = 0
16
17
 
17
18
  @buffer = ''
18
19
  end
19
20
 
20
- def push_mode(mode, indent)
21
+ def push_mode(mode, indent);
21
22
  super(mode, indent)
22
23
  end
23
24
 
@@ -30,13 +31,21 @@ module Orgmode
30
31
  def insert(line)
31
32
  # We try to get the lang from #+BEGIN_SRC blocks
32
33
  if line.begin_block?
33
- @block_lang = line.block_lang
34
- if line.block_header_arguments[':tangle']
34
+ case
35
+ when line.block_header_arguments[':tangle']
35
36
  @current_tangle = line.block_header_arguments[':tangle']
36
- else
37
- @shebang = line.block_header_arguments[':shebang']
37
+ when line.block_header_arguments[':shebang']
38
38
  @current_tangle = nil
39
39
  @buffer = ''
40
+
41
+ # Need to keep track of the options from a block before running it
42
+ @scripts[@scripts_counter][:header] = {
43
+ :shebang => line.block_header_arguments[':shebang']
44
+ }
45
+ @scripts[@scripts_counter][:lang] = line.block_lang
46
+
47
+ # TODO: have a way to specify which are the default binaries to be used per language
48
+ # when binary_detected?(@block_lang)
40
49
  end
41
50
  end
42
51
 
@@ -51,8 +60,9 @@ module Orgmode
51
60
  when (!@buffer.empty? and not (line.begin_block? or line.assigned_paragraph_type == :code))
52
61
  # Fix indentation and remove pre fix commas from Org mode before flushing
53
62
  strip_code_block!
54
- @scripts << @buffer
63
+ @scripts[@scripts_counter][:lines] << @buffer
55
64
  @buffer = ''
65
+ @scripts_counter += 1
56
66
  end
57
67
 
58
68
  @output_type = line.assigned_paragraph_type || line.paragraph_type
@@ -66,6 +76,7 @@ module Orgmode
66
76
  # TODO: This should be in the parent class....
67
77
  def output_footnotes!; false; end
68
78
 
79
+ # TODO: This should be part of some utils package from OrgRuby
69
80
  def strip_code_block!
70
81
  if @code_block_indent and @code_block_indent > 0
71
82
  strip_regexp = Regexp.new("^" + " " * @code_block_indent)
@@ -3,19 +3,21 @@ module OrgConverge
3
3
  attr_reader :dotorg
4
4
  attr_reader :logger
5
5
  attr_reader :ob
6
+ attr_reader :engine
6
7
 
7
8
  def initialize(options)
8
9
  @options = options
9
10
  @dotorg = options['<org_file>']
10
11
  @logger = Logger.new(options['--log'] || STDOUT)
11
12
  @root_dir = options['--root-dir']
12
- @ob = Orgmode::Parser.new(File.read(dotorg)).babelize
13
+ @run_dir = File.expand_path('run')
14
+ @ob = Orgmode::Parser.new(File.read(dotorg)).babelize
15
+ @babel = nil
13
16
  end
14
17
 
15
18
  def execute!
16
19
  case
17
20
  when @options['--showfiles']
18
-
19
21
  showfiles
20
22
  when @options['--tangle']
21
23
  tangle!
@@ -25,20 +27,37 @@ module OrgConverge
25
27
 
26
28
  true
27
29
  rescue => e
30
+ @logger.error e
28
31
  false
29
32
  end
30
33
 
31
34
  def converge!
32
35
  tangle!
36
+ run_blocks!
33
37
  end
34
38
 
35
39
  def tangle!
36
- begin
37
- babel = Orgmode::Babel.new(ob, { :logger => logger, :root_dir => @root_dir })
38
- results = babel.tangle!
39
- rescue Orgmode::Babel::TangleError
40
- logger.error "Cannot converge because there were errors during tangle step".red
40
+ results = babel.tangle!
41
+ rescue Orgmode::Babel::TangleError
42
+ logger.error "Cannot converge because there were errors during tangle step".red
43
+ end
44
+
45
+ # TODO: Too much foreman has made this running blocks in parallel the default behavior.
46
+ # We should actually be supporting run lists instead, but liking this experiment so far.
47
+ def run_blocks!
48
+ @engine = OrgConverge::Engine.new(:logger => @logger, :babel => @babel)
49
+ babel.tangle_runnable_blocks!(@run_dir)
50
+ babel.ob.scripts.each do |key, script|
51
+ file = File.expand_path("#{@run_dir}/#{key}")
52
+ cmd = "#{script[:lang]} #{file}"
53
+ @engine.register script[:lang], cmd, { :cwd => @root_dir, :logger => logger }
41
54
  end
55
+ logger.info "Running code blocks now! (#{babel.ob.scripts.count} runnable blocks found in total)"
56
+ @engine.start
57
+ end
58
+
59
+ def babel
60
+ @babel ||= Orgmode::Babel.new(ob, { :logger => @logger, :root_dir => @root_dir })
42
61
  end
43
62
 
44
63
  def showfiles
@@ -49,9 +68,9 @@ module OrgConverge
49
68
  end
50
69
  end
51
70
 
52
- ob.scripts.each_with_index do |script, index|
53
- puts "---------- script: #{index} --------------".green
54
- puts script
71
+ ob.scripts.each do |index, block|
72
+ puts "---------- script: #{index} to be run with: #{block[:header][:shebang]} --------------".green
73
+ puts block[:lines]
55
74
  end
56
75
  end
57
76
  end
@@ -0,0 +1,87 @@
1
+ #
2
+ # Re-use most of the proven tricks from Foreman for this
3
+ # and just customize to watch the output from runnable code blocks
4
+ #
5
+ require 'foreman/engine'
6
+ require 'foreman/process'
7
+
8
+ module OrgConverge
9
+ class Engine < Foreman::Engine
10
+
11
+ attr_reader :logger
12
+ attr_reader :babel
13
+
14
+ def initialize(options={})
15
+ super(options)
16
+ @logger = options[:logger] || Logger.new(STDOUT)
17
+ @babel = options[:babel]
18
+ end
19
+
20
+ # We allow other processes to exit with 0 status
21
+ # to continue with the runlist
22
+ def start
23
+ register_signal_handlers
24
+ spawn_processes
25
+ watch_for_output
26
+ sleep 0.1
27
+ begin
28
+ status = watch_for_termination
29
+ end while @running.count > 0
30
+ logger.info "Run has completed successfully.".green
31
+ end
32
+
33
+ # Overriden: we do not consider process formations
34
+ def spawn_processes
35
+ @processes.each do |process|
36
+ reader, writer = create_pipe
37
+ begin
38
+ pid = process.run(:output => writer)
39
+ @names[process] = "#{@names[process]}(#{pid})"
40
+ writer.puts "started with pid #{pid}"
41
+ rescue Errno::ENOENT
42
+ writer.puts "unknown command: #{process.command}"
43
+ end
44
+ @running[pid] = [process]
45
+ @readers[pid] = reader
46
+ end
47
+ end
48
+
49
+ def register(name, command, options={})
50
+ options[:env] ||= env
51
+ options[:cwd] ||= File.dirname(command.split(" ").first)
52
+ process = OrgConverge::CodeBlockProcess.new(command, options)
53
+ @names[process] = name
54
+ @processes << process
55
+ end
56
+
57
+ def output(name, data)
58
+ data.to_s.lines.map(&:chomp).each do |message|
59
+
60
+ # FIXME: In case the process has finished before its lines where flushed
61
+ ps = name.empty? ? '<defunct>' : name.split('.').first
62
+ output = "#{pad_process_name(ps)}".yellow
63
+ output += " -- "
64
+ output += message
65
+ # FIXME: When the process has stopped already,
66
+ # the name of the process does not appear
67
+ logger.info output
68
+ end
69
+ rescue Errno::EPIPE
70
+ terminate_gracefully
71
+ end
72
+
73
+ private
74
+ def name_padding
75
+ @name_padding ||= begin
76
+ name_padding = @names.values.map { |n| n.length }.sort.last
77
+ [ 9, name_padding ].max
78
+ end
79
+ end
80
+
81
+ def pad_process_name(name)
82
+ name.ljust(name_padding, " ")
83
+ end
84
+ end
85
+
86
+ class CodeBlockProcess < Foreman::Process; end
87
+ end
@@ -1,3 +1,3 @@
1
1
  module OrgConverge
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/org-converge.gemspec CHANGED
@@ -16,4 +16,5 @@ Gem::Specification.new do |gem|
16
16
  gem.version = OrgConverge::VERSION
17
17
  gem.add_runtime_dependency('docopt', '0.5.0')
18
18
  gem.add_runtime_dependency('org-ruby', '~> 0.9.2')
19
+ gem.add_runtime_dependency('foreman', '~> 0.63.0')
19
20
  end
@@ -0,0 +1,31 @@
1
+ #+title: Running scripts in parallel
2
+
3
+ In the following example, the following 3 scripts should be run in parallel
4
+ with all output being flushed to the screen.
5
+
6
+ - Count some numbers with bash
7
+
8
+ #+begin_src sh :shebang #!/bin/bash
9
+ for i in `seq 1 5`; do
10
+ echo "Writing! $i"
11
+ echo "hello $i" >> out.log
12
+ sleep $(($RANDOM % 10))
13
+ done
14
+ #+end_src
15
+
16
+ - Count some numbers with ruby
17
+
18
+ #+begin_src ruby :shebang #!/usr/bin/ruby
19
+ 10.times do |n|
20
+ puts "And now writing! #{n}"
21
+ File.open("out.log", "a") {|f| f.puts "Hello again #{n}" }
22
+ sleep rand.round(2)
23
+ end
24
+ #+end_src
25
+
26
+ - Print some numbers with python
27
+
28
+ #+begin_src python :shebang #!/usr/bin/python
29
+ for i in range(0,3):
30
+ print i
31
+ #+end_src
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: org-converge
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-03-23 00:00:00.000000000 Z
12
+ date: 2014-03-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: docopt
16
- requirement: &70317759431040 !ruby/object:Gem::Requirement
16
+ requirement: &70243331730100 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - =
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 0.5.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70317759431040
24
+ version_requirements: *70243331730100
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: org-ruby
27
- requirement: &70317759430520 !ruby/object:Gem::Requirement
27
+ requirement: &70243331729260 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,7 +32,18 @@ dependencies:
32
32
  version: 0.9.2
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70317759430520
35
+ version_requirements: *70243331729260
36
+ - !ruby/object:Gem::Dependency
37
+ name: foreman
38
+ requirement: &70243331728140 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 0.63.0
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70243331728140
36
47
  description: A light configuration management tool for Org mode
37
48
  email:
38
49
  - waldemar.quevedo@gmail.com
@@ -42,8 +53,10 @@ extensions: []
42
53
  extra_rdoc_files: []
43
54
  files:
44
55
  - .gitmodules
56
+ - .travis.yml
45
57
  - Gemfile
46
58
  - LICENSE
59
+ - README.md
47
60
  - README.org
48
61
  - Rakefile
49
62
  - TODO
@@ -56,8 +69,10 @@ files:
56
69
  - lib/org-converge/babel.rb
57
70
  - lib/org-converge/babel_output_buffer.rb
58
71
  - lib/org-converge/command.rb
72
+ - lib/org-converge/engine.rb
59
73
  - lib/org-converge/version.rb
60
74
  - org-converge.gemspec
75
+ - spec/converge_examples/basic_run_example/setup.org
61
76
  - spec/converge_examples/basic_tangle/conf.yml.expected
62
77
  - spec/converge_examples/basic_tangle/setup.org
63
78
  - spec/converge_spec.rb
@@ -88,7 +103,9 @@ specification_version: 3
88
103
  summary: Provides an 'org-converge' command which can be used for tangling and running
89
104
  Org mode code blocks
90
105
  test_files:
106
+ - spec/converge_examples/basic_run_example/setup.org
91
107
  - spec/converge_examples/basic_tangle/conf.yml.expected
92
108
  - spec/converge_examples/basic_tangle/setup.org
93
109
  - spec/converge_spec.rb
94
110
  - spec/spec_helper.rb
111
+ has_rdoc: