org-converge 0.0.9 → 0.0.10
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.
- checksums.yaml +7 -0
- data/Gemfile +1 -0
- data/README.org +177 -53
- data/TODO +9 -3
- data/lib/org-converge/babel_output_buffer.rb +2 -1
- data/lib/org-converge/command.rb +16 -4
- data/lib/org-converge/version.rb +1 -1
- data/org-converge.gemspec +5 -4
- data/spec/converge_examples/basic_run_example/setup.org +1 -1
- data/spec/converge_examples/commented_block/run.org +4 -4
- data/spec/converge_examples/expected_results/spec.org +1 -1
- data/spec/converge_examples/expected_results/spec2.org +11 -26
- data/spec/converge_examples/linked_tasks/tasks.org +2 -2
- data/spec/converge_examples/multi_proc/run.org +347 -0
- data/spec/converge_examples/runlist_example/setup.org +1 -1
- data/spec/converge_spec.rb +15 -1
- metadata +57 -29
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: fd70719da7320b3897953946f0a2963b7357af63
|
|
4
|
+
data.tar.gz: 7132c1734caa2456114f35c029dad12615188073
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: a11513f0b8d6395a12cf9372d8ebc5fcbf7afeb45ff2dffae3bb6230b3137c4c163b3eea5282ff895793d4d00854345a2d7352d28d3a7ab5ba5987ca2ac7f329
|
|
7
|
+
data.tar.gz: 50ef8e63011189ffd2f02dacbb4f32357b2b4d8c2ad410611a2b79eb4873ed282a95877e1f5a6b5e748bf6d538a99d7f95b9998ce9d7e9ef4b819056983b6045
|
data/Gemfile
CHANGED
data/README.org
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
** Description
|
|
9
9
|
|
|
10
|
-
This
|
|
10
|
+
This is an experiment of using Org mode to
|
|
11
11
|
create documentable reproducible runs, borrowing some ideas
|
|
12
12
|
of what is possible to do with tools like =chef-solo=,
|
|
13
13
|
=rake=, =foreman=, etc...
|
|
@@ -18,15 +18,16 @@ of what is possible to do with tools like =chef-solo=,
|
|
|
18
18
|
|
|
19
19
|
** Motivation
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
/reproducible research
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
[[http://orgmode.org/worg/org-contrib/babel/Org Babel][Org Mode]] has proven to be flexible enough to write
|
|
22
|
+
[[http://www.jstatsoft.org/v46/i03][reproducible research papers]].
|
|
23
|
+
Then, I believe that configuring and setting up
|
|
24
|
+
a server for example, is something that could also be done using
|
|
25
|
+
the same approach, given that /converging/ the configuration
|
|
26
|
+
is a kind of run that one ought to be able to reproduce.
|
|
26
27
|
|
|
27
28
|
** Usage
|
|
28
29
|
|
|
29
|
-
To run the blocks in parallel
|
|
30
|
+
To run the blocks in parallel:
|
|
30
31
|
|
|
31
32
|
#+begin_src sh
|
|
32
33
|
org-converge path/to/setup-file.org --runmode=parallel
|
|
@@ -45,12 +46,121 @@ it is possible to make the blocks depend on one another.
|
|
|
45
46
|
org-converge path/to/setup-file.org --runmode=chained
|
|
46
47
|
#+end_src
|
|
47
48
|
|
|
49
|
+
In case the blocks have results blocks, it is possible to run
|
|
50
|
+
the blocks and matched against the results with the ~org-spec~ helper command:
|
|
51
|
+
|
|
52
|
+
#+begin_src sh
|
|
53
|
+
org-spec path/to/file-spec.org
|
|
54
|
+
#+end_src
|
|
55
|
+
|
|
48
56
|
*** Other commands available
|
|
49
57
|
|
|
50
58
|
: org-run # alias for org-converge
|
|
51
59
|
: org-tangle # just tangles the contents without running the blocks
|
|
52
60
|
|
|
53
|
-
**
|
|
61
|
+
** How it works
|
|
62
|
+
|
|
63
|
+
Org Converge uses a liberally extended version of Org Babel
|
|
64
|
+
features in order to give support for converging the configuration
|
|
65
|
+
of a server, and the [[https://github.com/wallyqs/org-ruby][Ruby implementation of the Org mode parser]]
|
|
66
|
+
which makes integrating with useful Ruby tools like foreman, rake, rspec and ohai more straightforward.
|
|
67
|
+
|
|
68
|
+
For example, using Org Babel we can easily spread config
|
|
69
|
+
files on a server by writing the following on a ~server.org~ file.
|
|
70
|
+
|
|
71
|
+
#+begin_src sh
|
|
72
|
+
,#+begin_src yaml :tangle /etc/component.yml
|
|
73
|
+
multitenant: false
|
|
74
|
+
status_port: 10004
|
|
75
|
+
,#+end_src
|
|
76
|
+
#+end_src
|
|
77
|
+
|
|
78
|
+
And then configure it by running it as follows, (considering we have
|
|
79
|
+
the correct permissions for tangling at =/etc/component.yml=):
|
|
80
|
+
|
|
81
|
+
#+begin_src sh
|
|
82
|
+
sudo org-converge server.org
|
|
83
|
+
#+end_src
|
|
84
|
+
|
|
85
|
+
Next, let's say that we no only one want to set the configured templates,
|
|
86
|
+
but that we also want to install some packages. In that case, we
|
|
87
|
+
should be able to do the following:
|
|
88
|
+
(Note: Currently, only named blocks would be run)
|
|
89
|
+
|
|
90
|
+
#+begin_src sh
|
|
91
|
+
,** Configuring the component
|
|
92
|
+
|
|
93
|
+
,#+begin_src yaml :tangle /etc/component.yml
|
|
94
|
+
multitenant: false
|
|
95
|
+
status_port: 10004
|
|
96
|
+
,#+end_src
|
|
97
|
+
|
|
98
|
+
,** Installing the dependencies
|
|
99
|
+
|
|
100
|
+
Need the following so that ~bundle install~ can compile
|
|
101
|
+
the native extensions correctly.
|
|
102
|
+
|
|
103
|
+
# Giving the block a name would make it run
|
|
104
|
+
|
|
105
|
+
,#+name: build_essentials
|
|
106
|
+
,#+begin_src sh
|
|
107
|
+
apt-get install build-essentials -y
|
|
108
|
+
,#+end_src
|
|
109
|
+
|
|
110
|
+
Then the following should work:
|
|
111
|
+
|
|
112
|
+
,#+name: bundle_install
|
|
113
|
+
,#+begin_src sh
|
|
114
|
+
cd project_path
|
|
115
|
+
bundle install
|
|
116
|
+
,#+end_src
|
|
117
|
+
#+end_src
|
|
118
|
+
|
|
119
|
+
Since we are using Org mode syntax, it is possible to reuse this setup file by including it.
|
|
120
|
+
|
|
121
|
+
#+begin_src sh
|
|
122
|
+
,#+TITLE: Another setup
|
|
123
|
+
|
|
124
|
+
Include the code blocks from the server into this:
|
|
125
|
+
,#+include: "server.org"
|
|
126
|
+
|
|
127
|
+
,#+name: install_org_mode
|
|
128
|
+
,#+begin_src sh
|
|
129
|
+
apt-get install org-mode -y
|
|
130
|
+
,#+end_src
|
|
131
|
+
#+end_src
|
|
132
|
+
|
|
133
|
+
#+end_src
|
|
134
|
+
|
|
135
|
+
** Examples
|
|
136
|
+
|
|
137
|
+
Currently there is support for the following kind of runs:
|
|
138
|
+
|
|
139
|
+
- runs where the blocks need to run sequentially (~--runmode=sequential~) ::
|
|
140
|
+
|
|
141
|
+
Each code block is part of a step to be ran
|
|
142
|
+
|
|
143
|
+
- runs where the blocks need to be run in parallel (~--runmode=parallel~) ::
|
|
144
|
+
|
|
145
|
+
One example of this is having what is supposed to be a distributed system running locally for development (where ~foreman~ would be used).
|
|
146
|
+
|
|
147
|
+
- runs where the blocks need to be run in sequence according to defined dependencies (~--runmode=chained~) ::
|
|
148
|
+
|
|
149
|
+
Set of runs that are usually covered by using something like rake, make, etc...
|
|
150
|
+
|
|
151
|
+
- runs where the blocks are run and matched against the expected results for testing (~--runmode=spec~) ::
|
|
152
|
+
|
|
153
|
+
Each block is run and there is an assertion to check whether the contents in ~#+RESULTS~ block match
|
|
154
|
+
|
|
155
|
+
Besides being able to specify which kind of run to use through an option, it is also possible
|
|
156
|
+
to define this within the Org mode file itself as an in buffer setting:
|
|
157
|
+
|
|
158
|
+
#+begin_src org
|
|
159
|
+
,#+TITLE: Defining the runmode as an in buffer setting
|
|
160
|
+
,#+runmode: sequential
|
|
161
|
+
#+end_src
|
|
162
|
+
|
|
163
|
+
*** Parallel runs
|
|
54
164
|
|
|
55
165
|
The following is an example of running 3 processes
|
|
56
166
|
in parallel by defining them as code blocks from
|
|
@@ -58,20 +168,20 @@ an Org mode file:
|
|
|
58
168
|
|
|
59
169
|
#+begin_src sh
|
|
60
170
|
,#+TITLE: Running Org babel processes in parallel
|
|
61
|
-
|
|
171
|
+
|
|
62
172
|
,* Print with different languages
|
|
63
|
-
|
|
173
|
+
|
|
64
174
|
,#+name: hello_from_bash
|
|
65
175
|
,#+begin_src sh :shebang #!/bin/bash
|
|
66
176
|
while true; do echo "hello world from bash"; sleep 1; done
|
|
67
177
|
,#+end_src
|
|
68
|
-
|
|
178
|
+
|
|
69
179
|
,#+name: hello_from_ruby
|
|
70
180
|
,#+begin_src ruby :shebang #!/usr/local/bin/ruby
|
|
71
181
|
$stdout.sync = true
|
|
72
182
|
loop { puts "hello world from ruby" ; sleep 1 }
|
|
73
183
|
,#+end_src
|
|
74
|
-
|
|
184
|
+
|
|
75
185
|
,#+name: hello_from_python
|
|
76
186
|
,#+begin_src python :shebang #!/usr/bin/python
|
|
77
187
|
import time
|
|
@@ -86,7 +196,7 @@ an Org mode file:
|
|
|
86
196
|
We store this in a file named =hello.org= and then run it as follows:
|
|
87
197
|
|
|
88
198
|
#+begin_src sh
|
|
89
|
-
org-
|
|
199
|
+
org-run hello.org
|
|
90
200
|
#+end_src
|
|
91
201
|
|
|
92
202
|
This would produce an output similar to the following:
|
|
@@ -94,7 +204,7 @@ This would produce an output similar to the following:
|
|
|
94
204
|
#+begin_src sh
|
|
95
205
|
[2014-05-04T19:23:40 +0900] Tangling 0 files...
|
|
96
206
|
[2014-05-04T19:23:40 +0900] Tangling succeeded!
|
|
97
|
-
[2014-05-04T19:23:40 +0900] Tangling 3 scripts within directory: /Users/
|
|
207
|
+
[2014-05-04T19:23:40 +0900] Tangling 3 scripts within directory: /Users/wallyqs/repos/org-converge/run...
|
|
98
208
|
[2014-05-04T19:23:40 +0900] Running code blocks now! (3 runnable blocks found in total)
|
|
99
209
|
[2014-05-04T19:23:40 +0900] hello_from_bash (4664) -- started with pid 4664
|
|
100
210
|
[2014-05-04T19:23:40 +0900] hello_from_ruby (4665) -- started with pid 4665
|
|
@@ -105,56 +215,70 @@ This would produce an output similar to the following:
|
|
|
105
215
|
[2014-05-04T19:23:42 +0900] hello_from_ruby (4665) -- hello world from ruby
|
|
106
216
|
#+end_src
|
|
107
217
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
Org Converge uses an liberally extended version of Org Babel
|
|
111
|
-
features in order to give support for converging the configuration
|
|
112
|
-
of a server.
|
|
113
|
-
|
|
114
|
-
For example, using Org Babel and macros we can easily spread config
|
|
115
|
-
files on a server by writing the following on a ~server.org~ file.
|
|
218
|
+
Also possible to specify the name of the block to be ran:
|
|
116
219
|
|
|
117
220
|
#+begin_src sh
|
|
118
|
-
|
|
119
|
-
multitenant: false
|
|
120
|
-
status_port: 10004
|
|
121
|
-
,#+end_src
|
|
221
|
+
org-run hello.org --name from_ruby
|
|
122
222
|
#+end_src
|
|
123
223
|
|
|
124
|
-
|
|
125
|
-
|
|
224
|
+
*** Spec mode
|
|
225
|
+
|
|
226
|
+
In case the Org mode file has a results block which represents the expected result,
|
|
227
|
+
there is an ~org-spec~ command which can be useful to check whether there is change.
|
|
228
|
+
For example, given the following file stored in ~test.org~:
|
|
126
229
|
|
|
127
230
|
#+begin_src sh
|
|
128
|
-
|
|
231
|
+
,#+TITLE: Expected results example
|
|
232
|
+
|
|
233
|
+
,#+name: hello
|
|
234
|
+
,#+begin_src ruby :results output
|
|
235
|
+
10.times do
|
|
236
|
+
puts "hola"
|
|
237
|
+
end
|
|
238
|
+
,#+end_src
|
|
239
|
+
|
|
240
|
+
,#+RESULTS: hello
|
|
241
|
+
,#+begin_example
|
|
242
|
+
hola
|
|
243
|
+
hola
|
|
244
|
+
hola
|
|
245
|
+
hola
|
|
246
|
+
hola
|
|
247
|
+
hola
|
|
248
|
+
hola
|
|
249
|
+
hola
|
|
250
|
+
hola
|
|
251
|
+
hola
|
|
252
|
+
,#+end_example
|
|
129
253
|
#+end_src
|
|
130
254
|
|
|
131
|
-
|
|
132
|
-
but that we also want to install some packages. In that case, we
|
|
133
|
-
should be able to do the following:
|
|
255
|
+
We can be able to verify whether this is still correct by running ~org-spec test.org~
|
|
134
256
|
|
|
135
257
|
#+begin_src sh
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
,#+begin_src yaml :tangle /etc/component.yml
|
|
139
|
-
multitenant: false
|
|
140
|
-
status_port: 10004
|
|
141
|
-
,#+end_src
|
|
142
|
-
|
|
143
|
-
,* Installing the dependencies
|
|
144
|
-
|
|
145
|
-
Need the following so that ~bundle install~ can compile
|
|
146
|
-
the native extensions correctly.
|
|
258
|
+
Checking results from 'hello' code block: OK
|
|
259
|
+
#+end_src
|
|
147
260
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
261
|
+
As an example, let's say that the behavior of the original code block changed, and now says hello 5 times instead.
|
|
262
|
+
In that case the output would be as follows:
|
|
263
|
+
|
|
264
|
+
#+begin_src diff
|
|
265
|
+
Checking results from 'hello' code block: DIFF
|
|
266
|
+
@@ -1,11 +1,6 @@
|
|
267
|
+
-hola
|
|
268
|
+
-hola
|
|
269
|
+
-hola
|
|
270
|
+
-hola
|
|
271
|
+
-hola
|
|
272
|
+
-hola
|
|
273
|
+
-hola
|
|
274
|
+
-hola
|
|
275
|
+
-hola
|
|
276
|
+
-hola
|
|
277
|
+
+hello
|
|
278
|
+
+hello
|
|
279
|
+
+hello
|
|
280
|
+
+hello
|
|
281
|
+
+hello
|
|
158
282
|
#+end_src
|
|
159
283
|
|
|
160
284
|
** Contributing
|
data/TODO
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
#+TODO: TODO | DONE CANCELED
|
|
3
3
|
#+startup: showeverything
|
|
4
4
|
|
|
5
|
-
* [0/
|
|
5
|
+
* [0/9] 0.1.0 version
|
|
6
6
|
|
|
7
7
|
- [ ] Macros can be loaded and applied to the configuration
|
|
8
8
|
- [ ] Actually support converging and idempotency (~--runmode=idempotent~)
|
|
@@ -14,9 +14,15 @@
|
|
|
14
14
|
- [ ] Display how the run would look like without making changes
|
|
15
15
|
: org-converge setupfile.org --dry-run
|
|
16
16
|
- [ ] Use :eval for evaling blocks (off by default)
|
|
17
|
-
- [ ] Can use
|
|
17
|
+
- [ ] Can use ~:dir~ for running a process relative to that directory
|
|
18
|
+
- [ ] Bugfix for when results blocks have only inline examples or images
|
|
19
|
+
- [ ] Bugfix for when the result from a ~org-spec~ run has non-zero exit status
|
|
18
20
|
|
|
19
|
-
* [1/1]
|
|
21
|
+
* [1/1] 0.0.10
|
|
22
|
+
|
|
23
|
+
- [X] Add ~:procs~ to code blocks to identify how many times it should run
|
|
24
|
+
|
|
25
|
+
* [1/1] 0.0.8, 0.0.9 version
|
|
20
26
|
|
|
21
27
|
- [X] ~org-spec~ exploration!
|
|
22
28
|
|
|
@@ -64,7 +64,8 @@ module Orgmode
|
|
|
64
64
|
:mkdirp => line.block_header_arguments[':mkdirp'],
|
|
65
65
|
:name => line.properties['block_name'],
|
|
66
66
|
:before => line.block_header_arguments[':before'],
|
|
67
|
-
:after => line.block_header_arguments[':after']
|
|
67
|
+
:after => line.block_header_arguments[':after'],
|
|
68
|
+
:procs => line.block_header_arguments[':procs'],
|
|
68
69
|
}
|
|
69
70
|
@scripts[@scripts_counter][:lang] = line.block_lang
|
|
70
71
|
# TODO: have a way to specify which are the default binaries to be used per language
|
data/lib/org-converge/command.rb
CHANGED
|
@@ -163,8 +163,7 @@ module OrgConverge
|
|
|
163
163
|
# Decision: Only run blocks which have a name
|
|
164
164
|
next unless script[:header][:name]
|
|
165
165
|
|
|
166
|
-
|
|
167
|
-
@engine.register display_name, cmd, { :cwd => @root_dir, :logger => logger }
|
|
166
|
+
run_procs(script, cmd)
|
|
168
167
|
end
|
|
169
168
|
logger.info "Running code blocks now! (#{babel.ob.scripts.count} runnable blocks found in total)"
|
|
170
169
|
@engine.start
|
|
@@ -178,8 +177,7 @@ module OrgConverge
|
|
|
178
177
|
scripts.each do |key, script|
|
|
179
178
|
file = File.expand_path("#{@run_dir}/#{key}")
|
|
180
179
|
cmd = "#{script[:lang]} #{file}"
|
|
181
|
-
|
|
182
|
-
@engine.register display_name, cmd, { :cwd => @root_dir, :logger => logger }
|
|
180
|
+
run_procs(script, cmd)
|
|
183
181
|
end
|
|
184
182
|
|
|
185
183
|
logger.info "Running code blocks now! (#{scripts.count} runnable blocks found in total)"
|
|
@@ -281,6 +279,7 @@ module OrgConverge
|
|
|
281
279
|
exit 1 if failed.count > 0
|
|
282
280
|
end
|
|
283
281
|
|
|
282
|
+
private
|
|
284
283
|
def diff(expected_lines, actual_lines)
|
|
285
284
|
output = ""
|
|
286
285
|
file_length_difference = 0
|
|
@@ -335,5 +334,18 @@ module OrgConverge
|
|
|
335
334
|
puts block[:lines]
|
|
336
335
|
end
|
|
337
336
|
end
|
|
337
|
+
|
|
338
|
+
def run_procs(script, cmd)
|
|
339
|
+
display_name = script[:header][:name]
|
|
340
|
+
if script[:header][:procs]
|
|
341
|
+
procs = script[:header][:procs].to_i
|
|
342
|
+
procs.times do |i|
|
|
343
|
+
proc_name = "#{display_name}-#{i}"
|
|
344
|
+
@engine.register proc_name, cmd, { :cwd => @root_dir, :logger => logger }
|
|
345
|
+
end
|
|
346
|
+
else
|
|
347
|
+
@engine.register display_name, cmd, { :cwd => @root_dir, :logger => logger }
|
|
348
|
+
end
|
|
349
|
+
end
|
|
338
350
|
end
|
|
339
351
|
end
|
data/lib/org-converge/version.rb
CHANGED
data/org-converge.gemspec
CHANGED
|
@@ -14,9 +14,10 @@ Gem::Specification.new do |gem|
|
|
|
14
14
|
gem.name = "org-converge"
|
|
15
15
|
gem.require_paths = ["lib"]
|
|
16
16
|
gem.version = OrgConverge::VERSION
|
|
17
|
-
gem.add_runtime_dependency('docopt', '~> 0.5
|
|
18
|
-
gem.add_runtime_dependency('org-ruby', '~> 0.9
|
|
19
|
-
gem.add_runtime_dependency('foreman', '~> 0.63
|
|
20
|
-
gem.add_runtime_dependency('tco', '~> 0.1
|
|
17
|
+
gem.add_runtime_dependency('docopt', '~> 0.5')
|
|
18
|
+
gem.add_runtime_dependency('org-ruby', '~> 0.9')
|
|
19
|
+
gem.add_runtime_dependency('foreman', '~> 0.63')
|
|
20
|
+
gem.add_runtime_dependency('tco', '~> 0.1')
|
|
21
21
|
gem.add_runtime_dependency('rake', '~> 10.3')
|
|
22
|
+
gem.add_runtime_dependency('diff-lcs', '~> 1.2')
|
|
22
23
|
end
|
|
@@ -8,27 +8,27 @@
|
|
|
8
8
|
** Runnable blocks
|
|
9
9
|
|
|
10
10
|
#+name: runnable_block_1
|
|
11
|
-
#+begin_src
|
|
11
|
+
#+begin_src bash :results output
|
|
12
12
|
echo "first" > output.log
|
|
13
13
|
#+end_src
|
|
14
14
|
|
|
15
15
|
** COMMENT Non runnable blocks
|
|
16
16
|
|
|
17
17
|
#+name: not_runnable_block_2
|
|
18
|
-
#+begin_src
|
|
18
|
+
#+begin_src bash :results output
|
|
19
19
|
echo "should not run" >> output.log
|
|
20
20
|
#+end_src
|
|
21
21
|
|
|
22
22
|
** More runnable blocks
|
|
23
23
|
|
|
24
24
|
#+name: runnable_block_3
|
|
25
|
-
#+begin_src
|
|
25
|
+
#+begin_src bash :results output
|
|
26
26
|
echo "third" >> output.log
|
|
27
27
|
#+end_src
|
|
28
28
|
|
|
29
29
|
*** COMMENT Not runnable block
|
|
30
30
|
|
|
31
31
|
#+name: not_runnable_block_4
|
|
32
|
-
#+begin_src
|
|
32
|
+
#+begin_src bash :results output
|
|
33
33
|
echo "fourth" >> output.log
|
|
34
34
|
#+end_src
|
|
@@ -7,7 +7,7 @@ results, we can try checking whether the contents from the code block
|
|
|
7
7
|
are evaling into what is being documented in the results block.
|
|
8
8
|
|
|
9
9
|
#+name: hello
|
|
10
|
-
#+begin_src
|
|
10
|
+
#+begin_src bash :results output code :exports both
|
|
11
11
|
for i in `seq 20`; do
|
|
12
12
|
echo "hello"
|
|
13
13
|
done
|
|
@@ -26,7 +26,7 @@ This one would fail near christmas, outside of Japan,
|
|
|
26
26
|
when the site is down, or there is a change in the rss.xml being provided.
|
|
27
27
|
|
|
28
28
|
#+name: christmas_check
|
|
29
|
-
#+begin_src
|
|
29
|
+
#+begin_src bash :results output
|
|
30
30
|
curl https://isitchristmas.com/rss.xml 2> /dev/null | grep title
|
|
31
31
|
# curl isitchristmastyet.com 2> /dev/null
|
|
32
32
|
#+end_src
|
|
@@ -34,29 +34,14 @@ curl https://isitchristmas.com/rss.xml 2> /dev/null | grep title
|
|
|
34
34
|
#+RESULTS: christmas_check
|
|
35
35
|
#+begin_example
|
|
36
36
|
<title>Is It Christmas?</title>
|
|
37
|
-
<title
|
|
38
|
-
<title
|
|
39
|
-
<title
|
|
40
|
-
<title
|
|
41
|
-
<title
|
|
42
|
-
<title
|
|
43
|
-
<title
|
|
44
|
-
<title
|
|
45
|
-
<title
|
|
46
|
-
<title
|
|
47
|
-
#+end_example
|
|
48
|
-
|
|
49
|
-
#+RESULTS: fetch_google
|
|
50
|
-
#+begin_example
|
|
51
|
-
<title>Is It Christmas?</title>
|
|
52
|
-
<title>いいえ</title>
|
|
53
|
-
<title>いいえ</title>
|
|
54
|
-
<title>いいえ</title>
|
|
55
|
-
<title>いいえ</title>
|
|
56
|
-
<title>いいえ</title>
|
|
57
|
-
<title>いいえ</title>
|
|
58
|
-
<title>いいえ</title>
|
|
59
|
-
<title>いいえ</title>
|
|
60
|
-
<title>いいえ</title>
|
|
61
|
-
<title>いいえ</title>
|
|
37
|
+
<title>NO</title>
|
|
38
|
+
<title>NO</title>
|
|
39
|
+
<title>NO</title>
|
|
40
|
+
<title>NO</title>
|
|
41
|
+
<title>NO</title>
|
|
42
|
+
<title>NO</title>
|
|
43
|
+
<title>NO</title>
|
|
44
|
+
<title>NO</title>
|
|
45
|
+
<title>NO</title>
|
|
46
|
+
<title>NO</title>
|
|
62
47
|
#+end_example
|
|
@@ -9,7 +9,7 @@ With ~:after first~, the ~second~ block becomes
|
|
|
9
9
|
a prerequisite of the ~first~ block.
|
|
10
10
|
|
|
11
11
|
#+name: second
|
|
12
|
-
#+begin_src
|
|
12
|
+
#+begin_src bash :after first
|
|
13
13
|
for i in `seq 5 10`; do
|
|
14
14
|
echo $i >> out.log
|
|
15
15
|
done
|
|
@@ -35,7 +35,7 @@ The same with ~:before all~, this would be executed
|
|
|
35
35
|
at the beginning.
|
|
36
36
|
|
|
37
37
|
#+name: prologue
|
|
38
|
-
#+begin_src
|
|
38
|
+
#+begin_src bash :before first :results output
|
|
39
39
|
echo "init" > out.log
|
|
40
40
|
#+end_src
|
|
41
41
|
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
#+TITLE: Sequential and Distributed runs to solve Problem #4 from Project Euler, written in Org mode Babel mode
|
|
2
|
+
#+startup: showeverything
|
|
3
|
+
|
|
4
|
+
[[https://projecteuler.net/problem=4][Problem #4]] from Project Euler reads as follows:
|
|
5
|
+
|
|
6
|
+
#+begin_quote
|
|
7
|
+
A palindromic number reads the same both ways.
|
|
8
|
+
The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.
|
|
9
|
+
Find the largest palindrome made from the product of two 3-digit numbers.
|
|
10
|
+
#+end_quote
|
|
11
|
+
|
|
12
|
+
We can notice the following from the problem:
|
|
13
|
+
|
|
14
|
+
- The definition of a palindrome ::
|
|
15
|
+
Can be implemented considering that the reverse list of chars should be identical to the original list.
|
|
16
|
+
|
|
17
|
+
- There is exponential growth ::
|
|
18
|
+
We look for the largest palindrome in the range of 3 digit numbers (100 - 999).
|
|
19
|
+
For this, we iterate 2 times on the range, multiply the entries and make the palindrome check.
|
|
20
|
+
|
|
21
|
+
*** First implementation: Sequential run to find the largest palindrome
|
|
22
|
+
|
|
23
|
+
A straightforward implementation of the problem is by iterating twice
|
|
24
|
+
over the same range and grabbing the highest largest number:
|
|
25
|
+
|
|
26
|
+
#+name: sequential_palindrome_check
|
|
27
|
+
#+begin_src ruby :results output
|
|
28
|
+
require 'benchmark'
|
|
29
|
+
|
|
30
|
+
def palindrome_check(number)
|
|
31
|
+
digits = number.to_s.split('').map(&:to_i)
|
|
32
|
+
reverse_is_equal = digits == digits.reverse ? true : false
|
|
33
|
+
|
|
34
|
+
reverse_is_equal
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
SMALLEST_NUMBER = 100
|
|
38
|
+
LARGEST_NUMBER = 999
|
|
39
|
+
|
|
40
|
+
last_palindrome = 0
|
|
41
|
+
last_x = 0
|
|
42
|
+
last_y = 0
|
|
43
|
+
bm = Benchmark.measure do
|
|
44
|
+
SMALLEST_NUMBER.upto(LARGEST_NUMBER).each do |i|
|
|
45
|
+
SMALLEST_NUMBER.upto(LARGEST_NUMBER).each do |j|
|
|
46
|
+
|
|
47
|
+
product = i * j
|
|
48
|
+
is_palindrome = palindrome_check(product)
|
|
49
|
+
if is_palindrome and product > last_palindrome
|
|
50
|
+
last_palindrome = product
|
|
51
|
+
last_x = i
|
|
52
|
+
last_y = j
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
puts "The largest palindrome within this range is: #{last_palindrome} (x: #{last_x}, y: #{last_y}) and it took #{bm}"
|
|
59
|
+
#+end_src
|
|
60
|
+
|
|
61
|
+
#+RESULTS:
|
|
62
|
+
: The largest palindrome within this range is: 906609 (x: 913, y: 993) and it took 16.36000
|
|
63
|
+
|
|
64
|
+
For 3 digits, this approach seems like good enough. But what if we
|
|
65
|
+
want to find out the largest palindrome number with 4 digits? Since
|
|
66
|
+
growth is exponential, running this in a single process will take a
|
|
67
|
+
while to finish.
|
|
68
|
+
|
|
69
|
+
*** Second implementation: Distributed parallel run to find the largest palindrome
|
|
70
|
+
|
|
71
|
+
One way to improve things is to parallelize the computation and
|
|
72
|
+
coordinating the aggregation of the results by using a message
|
|
73
|
+
bus. Borrowing [[http://blog.gopheracademy.com/plumbing-and-semantics][an idea]] in this case we use [[http://blog.gopheracademy.com/plumbing-and-semantics][NATS]].
|
|
74
|
+
|
|
75
|
+
The approach to take here will be:
|
|
76
|
+
|
|
77
|
+
- Split the ranges in subranges according to the number of subscribers
|
|
78
|
+
- Make each one of the subscribers do the computation for us and emit
|
|
79
|
+
the response with the results
|
|
80
|
+
- Collect the responses and identify the smallest, largest palindrome
|
|
81
|
+
within the range
|
|
82
|
+
|
|
83
|
+
For this run, we will have 10 checkers doing the calculation in
|
|
84
|
+
parallel, and one process collecting the replies.
|
|
85
|
+
|
|
86
|
+
#+name: dist_palindrome_checks_aggregator
|
|
87
|
+
#+begin_src ruby
|
|
88
|
+
# palindrome_checks_aggregator.rb
|
|
89
|
+
require 'nats/client'
|
|
90
|
+
require 'json'
|
|
91
|
+
|
|
92
|
+
sleep 6 # Wait for the checkers to be ready before sending compute requests
|
|
93
|
+
$stdout.sync = true
|
|
94
|
+
["TERM", "INT"].each { |sig| trap(sig) { NATS.stop } }
|
|
95
|
+
|
|
96
|
+
MIN_RANGE = 100
|
|
97
|
+
MAX_RANGE = 999
|
|
98
|
+
CHECKERS = 10
|
|
99
|
+
|
|
100
|
+
@checkers_responses = 0
|
|
101
|
+
@palindromes = []
|
|
102
|
+
|
|
103
|
+
NATS.start {
|
|
104
|
+
# Stop running at the same time as the nats-server
|
|
105
|
+
EM.add_timer(40) { NATS.stop; exit 0 }
|
|
106
|
+
NATS.subscribe('palindromes-check.responses') do |msg, reply, sub|
|
|
107
|
+
palindromes_computation = JSON.parse(msg)
|
|
108
|
+
puts "Thanks, got: #{palindromes_computation['palindromes_found'].count} palindromes."
|
|
109
|
+
@palindromes << palindromes_computation['palindromes_found'].flatten
|
|
110
|
+
@checkers_responses += 1
|
|
111
|
+
|
|
112
|
+
total = @palindromes.flatten.count
|
|
113
|
+
smallest = @palindromes.flatten.min
|
|
114
|
+
largest = @palindromes.flatten.max
|
|
115
|
+
puts ">>>> So far we have found #{total} palindromes between #{MIN_RANGE} and #{MAX_RANGE}"
|
|
116
|
+
puts ">>>> The smallest one is #{smallest}"
|
|
117
|
+
puts ">>>> The largest one is #{largest}"
|
|
118
|
+
File.open('result', 'w') {|f| f.puts largest }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
balanced_check = MAX_RANGE / CHECKERS
|
|
122
|
+
|
|
123
|
+
ranges = []
|
|
124
|
+
min_range = MIN_RANGE
|
|
125
|
+
begin
|
|
126
|
+
next_min_range = min_range + balanced_check
|
|
127
|
+
ranges << [min_range, next_min_range - 1]
|
|
128
|
+
min_range = next_min_range
|
|
129
|
+
end while min_range < MAX_RANGE
|
|
130
|
+
|
|
131
|
+
ranges.each do |range|
|
|
132
|
+
range_start = range.first
|
|
133
|
+
range_finish = [range.last, MAX_RANGE].min
|
|
134
|
+
range_info = {'start' => range_start, 'upto' => range_finish, 'min' => MIN_RANGE, 'max' => MAX_RANGE}
|
|
135
|
+
|
|
136
|
+
# Only want one checker to respond to this
|
|
137
|
+
NATS.request('palindromes-check.requests', nil, :max => 1) do |response|
|
|
138
|
+
checker_info = JSON.parse(response)
|
|
139
|
+
puts "Sending compute request to: #{checker_info}: #{range_info}"
|
|
140
|
+
NATS.publish("palindromes-check.#{checker_info['checker_id']}.compute", range_info.to_json) do
|
|
141
|
+
puts "Registered: #{range_info} to be done by #{checker_info['checker_id']}."
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
end
|
|
146
|
+
}
|
|
147
|
+
#+end_src
|
|
148
|
+
|
|
149
|
+
And each one of the checkers, has code as the one below to be able to
|
|
150
|
+
announce itself. Setting ~:procs 10~ to match the number of checkers
|
|
151
|
+
in the aggregator.
|
|
152
|
+
|
|
153
|
+
#+name: dist_palindrome_checker
|
|
154
|
+
#+begin_src ruby :procs 10
|
|
155
|
+
# palindrome_checker.rb
|
|
156
|
+
require 'nats/client'
|
|
157
|
+
require 'securerandom'
|
|
158
|
+
require 'json'
|
|
159
|
+
|
|
160
|
+
sleep 4 # wait a little before the server starts
|
|
161
|
+
$stdout.sync = true
|
|
162
|
+
|
|
163
|
+
CHECKER_ID = SecureRandom.uuid
|
|
164
|
+
CHECKER_INFO = {'checker_id' => CHECKER_ID }
|
|
165
|
+
|
|
166
|
+
@offerings = 0
|
|
167
|
+
@palindromes = []
|
|
168
|
+
|
|
169
|
+
def palindrome_check(number)
|
|
170
|
+
digits = number.to_s.split('').map(&:to_i)
|
|
171
|
+
reverse_is_equal = digits == digits.reverse ? true : false
|
|
172
|
+
|
|
173
|
+
reverse_is_equal
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def compute_palindromes_in_range(range_info)
|
|
177
|
+
range = JSON.parse(range_info)
|
|
178
|
+
|
|
179
|
+
range_min = range['min']
|
|
180
|
+
range_max = range['max']
|
|
181
|
+
range_start = range['start']
|
|
182
|
+
range_upto = range['upto']
|
|
183
|
+
|
|
184
|
+
range_min.upto(range_max) do |i|
|
|
185
|
+
# Split this subrange among other checkers
|
|
186
|
+
range_start.upto(range_upto) do |j|
|
|
187
|
+
product = i * j
|
|
188
|
+
is_palindrome = palindrome_check(product)
|
|
189
|
+
@palindromes << product if is_palindrome
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
results = {'palindromes_found' => @palindromes }
|
|
194
|
+
|
|
195
|
+
results
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
NATS.start do
|
|
199
|
+
puts "[#{CHECKER_ID}] Ready for requests"
|
|
200
|
+
NATS.subscribe('palindromes-check.requests') do |msg, reply, sub|
|
|
201
|
+
EM.add_timer(@offerings) { NATS.publish(reply, CHECKER_INFO.to_json) }
|
|
202
|
+
@offerings += 1
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
NATS.subscribe("palindromes-check.#{CHECKER_ID}.compute") do |msg, reply, sub|
|
|
206
|
+
puts "Start working on: #{msg}"
|
|
207
|
+
results = compute_palindromes_in_range(msg)
|
|
208
|
+
@offerings -= 1
|
|
209
|
+
NATS.publish("palindromes-check.responses", results.to_json) do
|
|
210
|
+
puts "I'm done then."
|
|
211
|
+
NATS.stop
|
|
212
|
+
exit 0
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
#+end_src
|
|
217
|
+
|
|
218
|
+
**** Starting the run
|
|
219
|
+
|
|
220
|
+
Ruby implementation of NATS can be installed with:
|
|
221
|
+
|
|
222
|
+
#+begin_src sh
|
|
223
|
+
gem list | grep nats.*0.5.0.beta.12
|
|
224
|
+
[ $? -ne 0 ] && gem install nats --pre
|
|
225
|
+
#+end_src
|
|
226
|
+
|
|
227
|
+
And we execute the run as follows:
|
|
228
|
+
|
|
229
|
+
#+name: dist_nats_server_daemon
|
|
230
|
+
#+begin_src bash
|
|
231
|
+
# timeout nats in 30 seconds
|
|
232
|
+
(bundle exec nats-server) & sleep 40; kill $! 2> /dev/null || :
|
|
233
|
+
#+end_src
|
|
234
|
+
|
|
235
|
+
: palindrome_checks_aggregator.rb &
|
|
236
|
+
: for i in `seq 1 10`; do
|
|
237
|
+
: ruby palindrome_checker.rb &
|
|
238
|
+
: done
|
|
239
|
+
|
|
240
|
+
Or since this Gist is also written in literate Org mode style, it can be run as follows:
|
|
241
|
+
|
|
242
|
+
: gem install org-converge
|
|
243
|
+
: org-run palindromes.org
|
|
244
|
+
|
|
245
|
+
Sample output from this would look like this:
|
|
246
|
+
|
|
247
|
+
#+begin_src sh
|
|
248
|
+
[2014-05-27T04:40:51 +0900] Tangling 0 files...
|
|
249
|
+
[2014-05-27T04:40:51 +0900] Tangling succeeded!
|
|
250
|
+
[2014-05-27T04:40:51 +0900] Tangling 7 scripts within directory: /Users/mariko/Dropbox/repos/org-converge/run...
|
|
251
|
+
[2014-05-27T04:40:51 +0900] Running code blocks now! (7 runnable blocks found in total)
|
|
252
|
+
[2014-05-27T04:40:52 +0900] sequential_palindrome_check (87486) -- started with pid 87486
|
|
253
|
+
[2014-05-27T04:40:52 +0900] dist_palindrome_checks_aggregator (87487) -- started with pid 87487
|
|
254
|
+
[2014-05-27T04:40:52 +0900] dist_palindrome_checker-0 (87489) -- started with pid 87489
|
|
255
|
+
[2014-05-27T04:40:52 +0900] dist_palindrome_checker-1 (87491) -- started with pid 87491
|
|
256
|
+
[2014-05-27T04:40:52 +0900] dist_palindrome_checker-2 (87493) -- started with pid 87493
|
|
257
|
+
[2014-05-27T04:40:52 +0900] dist_palindrome_checker-3 (87494) -- started with pid 87494
|
|
258
|
+
[2014-05-27T04:40:52 +0900] dist_palindrome_checker-4 (87496) -- started with pid 87496
|
|
259
|
+
[2014-05-27T04:40:52 +0900] dist_palindrome_checker-5 (87498) -- started with pid 87498
|
|
260
|
+
[2014-05-27T04:40:52 +0900] dist_palindrome_checker-6 (87499) -- started with pid 87499
|
|
261
|
+
[2014-05-27T04:40:52 +0900] dist_palindrome_checker-7 (87500) -- started with pid 87500
|
|
262
|
+
[2014-05-27T04:40:52 +0900] dist_palindrome_checker-8 (87501) -- started with pid 87501
|
|
263
|
+
[2014-05-27T04:40:52 +0900] dist_palindrome_checker-9 (87502) -- started with pid 87502
|
|
264
|
+
[2014-05-27T04:40:52 +0900] dist_nats_server_daemon (87503) -- started with pid 87503
|
|
265
|
+
[2014-05-27T04:41:00 +0900] dist_palindrome_checker-0 (87489) -- [dc401559-c0c8-450b-a0fd-f2093b0f59e0] Ready for requests
|
|
266
|
+
[2014-05-27T04:41:00 +0900] dist_palindrome_checker-7 (87500) -- [7624024f-1be8-4962-aad6-aa2ae8366f0e] Ready for requests
|
|
267
|
+
[2014-05-27T04:41:00 +0900] dist_palindrome_checker-1 (87491) -- [218a8813-d5e9-4bc0-a206-c12ac5086126] Ready for requests
|
|
268
|
+
[2014-05-27T04:41:00 +0900] dist_palindrome_checker-4 (87496) -- [69b2b618-8a67-40c1-bf5a-988077a49251] Ready for requests
|
|
269
|
+
[2014-05-27T04:41:00 +0900] dist_palindrome_checker-8 (87501) -- [1e11550a-d609-461e-8ec6-9eae82c27ac6] Ready for requests
|
|
270
|
+
[2014-05-27T04:41:00 +0900] dist_palindrome_checker-2 (87493) -- [d1148625-360a-49ff-bd4d-257fecd9e7d6] Ready for requests
|
|
271
|
+
[2014-05-27T04:41:00 +0900] dist_palindrome_checker-5 (87498) -- [e72b34e7-22ff-42e0-9d6b-92aa26e15ace] Ready for requests
|
|
272
|
+
[2014-05-27T04:41:00 +0900] dist_palindrome_checker-3 (87494) -- [2f2b4180-3fcf-4461-8b59-632fdd5236a7] Ready for requests
|
|
273
|
+
[2014-05-27T04:41:00 +0900] dist_palindrome_checker-6 (87499) -- [d5129048-0994-4cd3-9cae-44c0d394de1e] Ready for requests
|
|
274
|
+
[2014-05-27T04:41:00 +0900] dist_palindrome_checker-9 (87502) -- [5c2b3866-41dd-4338-9c28-343d28291853] Ready for requests
|
|
275
|
+
[2014-05-27T04:41:02 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"dc401559-c0c8-450b-a0fd-f2093b0f59e0"}: {"start"=>100, "upto"=>198, "min"=>100, "max"=>999}
|
|
276
|
+
[2014-05-27T04:41:02 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>100, "upto"=>198, "min"=>100, "max"=>999} to be done by dc401559-c0c8-450b-a0fd-f2093b0f59e0.
|
|
277
|
+
[2014-05-27T04:41:02 +0900] dist_palindrome_checker-0 (87489) -- Start working on: {"start":100,"upto":198,"min":100,"max":999}
|
|
278
|
+
[2014-05-27T04:41:03 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"7624024f-1be8-4962-aad6-aa2ae8366f0e"}: {"start"=>199, "upto"=>297, "min"=>100, "max"=>999}
|
|
279
|
+
[2014-05-27T04:41:03 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>199, "upto"=>297, "min"=>100, "max"=>999} to be done by 7624024f-1be8-4962-aad6-aa2ae8366f0e.
|
|
280
|
+
[2014-05-27T04:41:03 +0900] dist_palindrome_checker-7 (87500) -- Start working on: {"start":199,"upto":297,"min":100,"max":999}
|
|
281
|
+
[2014-05-27T04:41:04 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"218a8813-d5e9-4bc0-a206-c12ac5086126"}: {"start"=>298, "upto"=>396, "min"=>100, "max"=>999}
|
|
282
|
+
[2014-05-27T04:41:04 +0900] dist_palindrome_checker-1 (87491) -- Start working on: {"start":298,"upto":396,"min":100,"max":999}
|
|
283
|
+
[2014-05-27T04:41:04 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>298, "upto"=>396, "min"=>100, "max"=>999} to be done by 218a8813-d5e9-4bc0-a206-c12ac5086126.
|
|
284
|
+
[2014-05-27T04:41:05 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"1e11550a-d609-461e-8ec6-9eae82c27ac6"}: {"start"=>397, "upto"=>495, "min"=>100, "max"=>999}
|
|
285
|
+
[2014-05-27T04:41:05 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>397, "upto"=>495, "min"=>100, "max"=>999} to be done by 1e11550a-d609-461e-8ec6-9eae82c27ac6.
|
|
286
|
+
[2014-05-27T04:41:05 +0900] dist_palindrome_checker-8 (87501) -- Start working on: {"start":397,"upto":495,"min":100,"max":999}
|
|
287
|
+
[2014-05-27T04:41:06 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"d1148625-360a-49ff-bd4d-257fecd9e7d6"}: {"start"=>496, "upto"=>594, "min"=>100, "max"=>999}
|
|
288
|
+
[2014-05-27T04:41:06 +0900] dist_palindrome_checker-2 (87493) -- Start working on: {"start":496,"upto":594,"min":100,"max":999}
|
|
289
|
+
[2014-05-27T04:41:06 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>496, "upto"=>594, "min"=>100, "max"=>999} to be done by d1148625-360a-49ff-bd4d-257fecd9e7d6.
|
|
290
|
+
[2014-05-27T04:41:07 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"69b2b618-8a67-40c1-bf5a-988077a49251"}: {"start"=>595, "upto"=>693, "min"=>100, "max"=>999}
|
|
291
|
+
[2014-05-27T04:41:07 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>595, "upto"=>693, "min"=>100, "max"=>999} to be done by 69b2b618-8a67-40c1-bf5a-988077a49251.
|
|
292
|
+
[2014-05-27T04:41:07 +0900] dist_palindrome_checker-4 (87496) -- Start working on: {"start":595,"upto":693,"min":100,"max":999}
|
|
293
|
+
[2014-05-27T04:41:08 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"d5129048-0994-4cd3-9cae-44c0d394de1e"}: {"start"=>694, "upto"=>792, "min"=>100, "max"=>999}
|
|
294
|
+
[2014-05-27T04:41:08 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>694, "upto"=>792, "min"=>100, "max"=>999} to be done by d5129048-0994-4cd3-9cae-44c0d394de1e.
|
|
295
|
+
[2014-05-27T04:41:08 +0900] dist_palindrome_checker-6 (87499) -- Start working on: {"start":694,"upto":792,"min":100,"max":999}
|
|
296
|
+
[2014-05-27T04:41:09 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"e72b34e7-22ff-42e0-9d6b-92aa26e15ace"}: {"start"=>793, "upto"=>891, "min"=>100, "max"=>999}
|
|
297
|
+
[2014-05-27T04:41:09 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>793, "upto"=>891, "min"=>100, "max"=>999} to be done by e72b34e7-22ff-42e0-9d6b-92aa26e15ace.
|
|
298
|
+
[2014-05-27T04:41:09 +0900] dist_palindrome_checker-5 (87498) -- Start working on: {"start":793,"upto":891,"min":100,"max":999}
|
|
299
|
+
[2014-05-27T04:41:10 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 658 palindromes.
|
|
300
|
+
[2014-05-27T04:41:10 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 658 palindromes between 100 and 999
|
|
301
|
+
[2014-05-27T04:41:10 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
|
|
302
|
+
[2014-05-27T04:41:10 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 180081
|
|
303
|
+
[2014-05-27T04:41:10 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"2f2b4180-3fcf-4461-8b59-632fdd5236a7"}: {"start"=>892, "upto"=>990, "min"=>100, "max"=>999}
|
|
304
|
+
[2014-05-27T04:41:10 +0900] dist_palindrome_checker-3 (87494) -- Start working on: {"start":892,"upto":990,"min":100,"max":999}
|
|
305
|
+
[2014-05-27T04:41:10 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>892, "upto"=>990, "min"=>100, "max"=>999} to be done by 2f2b4180-3fcf-4461-8b59-632fdd5236a7.
|
|
306
|
+
[2014-05-27T04:41:11 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"dc401559-c0c8-450b-a0fd-f2093b0f59e0"}: {"start"=>991, "upto"=>999, "min"=>100, "max"=>999}
|
|
307
|
+
[2014-05-27T04:41:11 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>991, "upto"=>999, "min"=>100, "max"=>999} to be done by dc401559-c0c8-450b-a0fd-f2093b0f59e0.
|
|
308
|
+
[2014-05-27T04:41:11 +0900] dist_palindrome_checker-0 (87489) -- Start working on: {"start":991,"upto":999,"min":100,"max":999}
|
|
309
|
+
[2014-05-27T04:41:12 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 662 palindromes.
|
|
310
|
+
[2014-05-27T04:41:12 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 1320 palindromes between 100 and 999
|
|
311
|
+
[2014-05-27T04:41:12 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
|
|
312
|
+
[2014-05-27T04:41:12 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 906609
|
|
313
|
+
[2014-05-27T04:41:14 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 422 palindromes.
|
|
314
|
+
[2014-05-27T04:41:14 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 1742 palindromes between 100 and 999
|
|
315
|
+
[2014-05-27T04:41:14 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
|
|
316
|
+
[2014-05-27T04:41:14 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 906609
|
|
317
|
+
[2014-05-27T04:41:16 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 287 palindromes.
|
|
318
|
+
[2014-05-27T04:41:16 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 2029 palindromes between 100 and 999
|
|
319
|
+
[2014-05-27T04:41:16 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
|
|
320
|
+
[2014-05-27T04:41:16 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 906609
|
|
321
|
+
[2014-05-27T04:41:18 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 265 palindromes.
|
|
322
|
+
[2014-05-27T04:41:18 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 2294 palindromes between 100 and 999
|
|
323
|
+
[2014-05-27T04:41:18 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
|
|
324
|
+
[2014-05-27T04:41:18 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 906609
|
|
325
|
+
[2014-05-27T04:41:20 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 204 palindromes.
|
|
326
|
+
[2014-05-27T04:41:20 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 2498 palindromes between 100 and 999
|
|
327
|
+
[2014-05-27T04:41:20 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
|
|
328
|
+
[2014-05-27T04:41:20 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 906609
|
|
329
|
+
[2014-05-27T04:41:20 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 175 palindromes.
|
|
330
|
+
[2014-05-27T04:41:20 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 2673 palindromes between 100 and 999
|
|
331
|
+
[2014-05-27T04:41:20 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
|
|
332
|
+
[2014-05-27T04:41:20 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 906609
|
|
333
|
+
[2014-05-27T04:41:21 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 162 palindromes.
|
|
334
|
+
[2014-05-27T04:41:21 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 2835 palindromes between 100 and 999
|
|
335
|
+
[2014-05-27T04:41:21 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
|
|
336
|
+
[2014-05-27T04:41:21 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 906609
|
|
337
|
+
[2014-05-27T04:41:21 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 154 palindromes.
|
|
338
|
+
[2014-05-27T04:41:21 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 2989 palindromes between 100 and 999
|
|
339
|
+
[2014-05-27T04:41:21 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
|
|
340
|
+
[2014-05-27T04:41:21 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 906609
|
|
341
|
+
[2014-05-27T04:41:22 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 139 palindromes.
|
|
342
|
+
[2014-05-27T04:41:22 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 3128 palindromes between 100 and 999
|
|
343
|
+
[2014-05-27T04:41:22 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
|
|
344
|
+
[2014-05-27T04:41:22 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 906609
|
|
345
|
+
[2014-05-27T04:41:34 +0900] sequential_palindrome_check (87486) -- The largest palindrome within this range is: 906609 (x: 913, y: 993) and it took 18.470000 0.270000 18.740000 ( 38.710531)
|
|
346
|
+
[2014-05-27T04:41:34 +0900] sequential_palindrome_check (87486) -- exited with code 0
|
|
347
|
+
#+end_src
|
data/spec/converge_spec.rb
CHANGED
|
@@ -119,7 +119,7 @@ describe OrgConverge::Command do
|
|
|
119
119
|
success.should == true
|
|
120
120
|
end
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
pending "should run 'expected_results' with example blocks" do
|
|
123
123
|
example_dir = File.join(EXAMPLES_DIR, 'expected_results')
|
|
124
124
|
setup_file = File.join(example_dir, 'spec2.org')
|
|
125
125
|
|
|
@@ -131,4 +131,18 @@ describe OrgConverge::Command do
|
|
|
131
131
|
success = o.execute!
|
|
132
132
|
success.should == true
|
|
133
133
|
end
|
|
134
|
+
|
|
135
|
+
it "should run 'multi_proc' with the same number of defined :procs" do
|
|
136
|
+
example_dir = File.join(EXAMPLES_DIR, 'multi_proc')
|
|
137
|
+
setup_file = File.join(example_dir, 'run.org')
|
|
138
|
+
|
|
139
|
+
o = OrgConverge::Command.new({
|
|
140
|
+
'<org_file>' => setup_file,
|
|
141
|
+
'--root-dir' => example_dir
|
|
142
|
+
})
|
|
143
|
+
success = o.execute!
|
|
144
|
+
success.should == true
|
|
145
|
+
largest = File.open("#{example_dir}/result").read
|
|
146
|
+
largest.should == "906609\n"
|
|
147
|
+
end
|
|
134
148
|
end
|
metadata
CHANGED
|
@@ -1,71 +1,99 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: org-converge
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
5
|
-
prerelease:
|
|
4
|
+
version: 0.0.10
|
|
6
5
|
platform: ruby
|
|
7
6
|
authors:
|
|
8
7
|
- Waldemar Quevedo
|
|
9
8
|
autorequire:
|
|
10
9
|
bindir: bin
|
|
11
10
|
cert_chain: []
|
|
12
|
-
date: 2014-05-
|
|
11
|
+
date: 2014-05-26 00:00:00.000000000 Z
|
|
13
12
|
dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
|
15
14
|
name: docopt
|
|
16
|
-
requirement:
|
|
17
|
-
none: false
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
18
16
|
requirements:
|
|
19
17
|
- - ~>
|
|
20
18
|
- !ruby/object:Gem::Version
|
|
21
|
-
version: 0.5
|
|
19
|
+
version: '0.5'
|
|
22
20
|
type: :runtime
|
|
23
21
|
prerelease: false
|
|
24
|
-
version_requirements:
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ~>
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0.5'
|
|
25
27
|
- !ruby/object:Gem::Dependency
|
|
26
28
|
name: org-ruby
|
|
27
|
-
requirement:
|
|
28
|
-
none: false
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
30
|
requirements:
|
|
30
31
|
- - ~>
|
|
31
32
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 0.9
|
|
33
|
+
version: '0.9'
|
|
33
34
|
type: :runtime
|
|
34
35
|
prerelease: false
|
|
35
|
-
version_requirements:
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ~>
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0.9'
|
|
36
41
|
- !ruby/object:Gem::Dependency
|
|
37
42
|
name: foreman
|
|
38
|
-
requirement:
|
|
39
|
-
none: false
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
40
44
|
requirements:
|
|
41
45
|
- - ~>
|
|
42
46
|
- !ruby/object:Gem::Version
|
|
43
|
-
version: 0.63
|
|
47
|
+
version: '0.63'
|
|
44
48
|
type: :runtime
|
|
45
49
|
prerelease: false
|
|
46
|
-
version_requirements:
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ~>
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0.63'
|
|
47
55
|
- !ruby/object:Gem::Dependency
|
|
48
56
|
name: tco
|
|
49
|
-
requirement:
|
|
50
|
-
none: false
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
51
58
|
requirements:
|
|
52
59
|
- - ~>
|
|
53
60
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: 0.1
|
|
61
|
+
version: '0.1'
|
|
55
62
|
type: :runtime
|
|
56
63
|
prerelease: false
|
|
57
|
-
version_requirements:
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ~>
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0.1'
|
|
58
69
|
- !ruby/object:Gem::Dependency
|
|
59
70
|
name: rake
|
|
60
|
-
requirement:
|
|
61
|
-
none: false
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
62
72
|
requirements:
|
|
63
73
|
- - ~>
|
|
64
74
|
- !ruby/object:Gem::Version
|
|
65
75
|
version: '10.3'
|
|
66
76
|
type: :runtime
|
|
67
77
|
prerelease: false
|
|
68
|
-
version_requirements:
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ~>
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '10.3'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: diff-lcs
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ~>
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '1.2'
|
|
90
|
+
type: :runtime
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ~>
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '1.2'
|
|
69
97
|
description: A light configuration management tool for Org mode
|
|
70
98
|
email:
|
|
71
99
|
- waldemar.quevedo@gmail.com
|
|
@@ -106,33 +134,33 @@ files:
|
|
|
106
134
|
- spec/converge_examples/expected_results/spec.org
|
|
107
135
|
- spec/converge_examples/expected_results/spec2.org
|
|
108
136
|
- spec/converge_examples/linked_tasks/tasks.org
|
|
137
|
+
- spec/converge_examples/multi_proc/run.org
|
|
109
138
|
- spec/converge_examples/runlist_example/setup.org
|
|
110
139
|
- spec/converge_examples/specified_block/run.org
|
|
111
140
|
- spec/converge_spec.rb
|
|
112
141
|
- spec/spec_helper.rb
|
|
113
142
|
homepage: https://github.com/wallyqs/org-converge
|
|
114
143
|
licenses: []
|
|
144
|
+
metadata: {}
|
|
115
145
|
post_install_message:
|
|
116
146
|
rdoc_options: []
|
|
117
147
|
require_paths:
|
|
118
148
|
- lib
|
|
119
149
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
120
|
-
none: false
|
|
121
150
|
requirements:
|
|
122
|
-
- -
|
|
151
|
+
- - '>='
|
|
123
152
|
- !ruby/object:Gem::Version
|
|
124
153
|
version: '0'
|
|
125
154
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
126
|
-
none: false
|
|
127
155
|
requirements:
|
|
128
|
-
- -
|
|
156
|
+
- - '>='
|
|
129
157
|
- !ruby/object:Gem::Version
|
|
130
158
|
version: '0'
|
|
131
159
|
requirements: []
|
|
132
160
|
rubyforge_project:
|
|
133
|
-
rubygems_version:
|
|
161
|
+
rubygems_version: 2.2.2
|
|
134
162
|
signing_key:
|
|
135
|
-
specification_version:
|
|
163
|
+
specification_version: 4
|
|
136
164
|
summary: Provides an 'org-converge' command which can be used for tangling and running
|
|
137
165
|
Org mode code blocks
|
|
138
166
|
test_files:
|
|
@@ -143,8 +171,8 @@ test_files:
|
|
|
143
171
|
- spec/converge_examples/expected_results/spec.org
|
|
144
172
|
- spec/converge_examples/expected_results/spec2.org
|
|
145
173
|
- spec/converge_examples/linked_tasks/tasks.org
|
|
174
|
+
- spec/converge_examples/multi_proc/run.org
|
|
146
175
|
- spec/converge_examples/runlist_example/setup.org
|
|
147
176
|
- spec/converge_examples/specified_block/run.org
|
|
148
177
|
- spec/converge_spec.rb
|
|
149
178
|
- spec/spec_helper.rb
|
|
150
|
-
has_rdoc:
|