carrousel 0.0.4
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 +15 -0
- data/.gitignore +17 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +59 -0
- data/Rakefile +8 -0
- data/bin/carrousel +45 -0
- data/carrousel.gemspec +29 -0
- data/lib/carrousel.rb +101 -0
- data/lib/carrousel/version.rb +3 -0
- data/test/minitest_helper.rb +4 -0
- data/test/test_carrousel.rb +11 -0
- metadata +106 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZDllYjNiM2Y5MzY0NDI0MzEyZDZhMTZlNGM0MDY3N2EwYTJiZTY5Zg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YjhlYzMzNDBlNzE0OTg2YmM5NjIxZmY0NTY2NzZhODE2YTM4NDhlMQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MmRjYWJjNjI1Y2M1NmExNjI0NzIxZGZjZTRkM2QxZjdmMTMzNjM0MDU1MjAx
|
10
|
+
MzYxZjI3MjUyZTlhY2NmYTZhYmRhZDZhODlkZTMzOTM2YjIxYmQwZWNjMjE2
|
11
|
+
ZjY5ZTYxNjI2ODZkZmUxZTI2NzkwODVjMzk3NzUxZGIyZTZiNTM=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YWJiZWI4YjViZmJkZTk4ZTIyNDllOWZlZGQ1ZmYxODFhMDNmMjAwNGRhZjgy
|
14
|
+
N2EwMGY3MDVmY2ZjZTFmZTk1OTQ1Mzk5ODdlYjNlNjJkNGFkOGY5NzIzNDQ5
|
15
|
+
MmRhYWQxMzJhMjU5ODljMDAwNTcxOGQ5NDRlZmZmZWRiYzM1YzY=
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Raj Sahae
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# Carrousel
|
2
|
+
|
3
|
+
The Carrousel gem is a command line utility for running a single command on
|
4
|
+
multiple targets. Carrousel tracks which commands have succeeded or failed
|
5
|
+
based on the return of the system call, and sends failed jobs to the back of
|
6
|
+
the line to be tried again later.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
gem 'carrousel'
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install carrousel
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
The most basic use case for Carrousel is to give it a command and a list of
|
25
|
+
items as command line arguments:
|
26
|
+
|
27
|
+
$ carrousel -c 'echo' foo bar baz
|
28
|
+
|
29
|
+
In addition to passing in arguments on the command line, you can also pass them
|
30
|
+
in a file. These will be in addition to anything on the command line:
|
31
|
+
|
32
|
+
$ carrousel -c 'echo' -l things-to-echo.txt foo bar baz
|
33
|
+
|
34
|
+
While running, carrousel will track it's progress in a carrousel runner status
|
35
|
+
file. This file is stored in the present working directory. If you need to kill
|
36
|
+
carrousel for any reason, you can pick up where you left off by passing the
|
37
|
+
status file into carrousel. The status file will save your completed items,
|
38
|
+
incompleted items, and the command used. The file will always be of the form
|
39
|
+
~/PWD/.carrousel\_runner\_status\_XXXXXXX. The following example kills the echo
|
40
|
+
carrousel and resumes it using a carrousel runner status file:
|
41
|
+
|
42
|
+
$ carrousel -c 'echo' foo bar baz
|
43
|
+
... CTRL-C to kill this for some reason ...
|
44
|
+
$ carrousel -s .carrousel\_runner\_status\_130b02b
|
45
|
+
|
46
|
+
If you would like there to be some sort of delay between individual jobs, you
|
47
|
+
can specify that with a delay argument. The following example inserts a 30
|
48
|
+
second delay between each echo command:
|
49
|
+
|
50
|
+
$ carrousel -c 'echo' --delay 30 foo bar baz
|
51
|
+
|
52
|
+
|
53
|
+
## Contributing
|
54
|
+
|
55
|
+
1. Fork it
|
56
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
57
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
58
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
59
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/carrousel
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'carrousel'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
@opts = {}
|
7
|
+
OptionParser.new do |op|
|
8
|
+
op.banner = "Usage: #{__FILE__} [options] -c COMMAND arg1 [arg2 ...]"
|
9
|
+
|
10
|
+
op.on('-c', '--command COMMAND', 'Execute the given COMMAND') do |c|
|
11
|
+
@opts[:command] = c
|
12
|
+
end
|
13
|
+
|
14
|
+
op.on('-d', '--delay DELAY', 'Sleep for DELAY seconds between commands') do |d|
|
15
|
+
@opts[:delay] = d.to_i
|
16
|
+
end
|
17
|
+
|
18
|
+
op.on('-l', '--listfile FILE', 'Load list of arguments from FILE') do |l|
|
19
|
+
@opts[:listfile] = File.expand_path(l)
|
20
|
+
end
|
21
|
+
|
22
|
+
op.on('-s', '--statusfile FILE', 'Replay FILE with saved command and args') do |s|
|
23
|
+
@opts[:statusfile] = File.expand_path(s)
|
24
|
+
end
|
25
|
+
|
26
|
+
op.on('-v', '--[no-]verbose', 'Enable verbose output') do |v|
|
27
|
+
@opts[:verbose] = v
|
28
|
+
end
|
29
|
+
|
30
|
+
op.on('--[no-]debug', 'Enable debug output') do |d|
|
31
|
+
@opts[:debug] = d
|
32
|
+
@opts[:verbose] ||= d
|
33
|
+
end
|
34
|
+
end.parse!
|
35
|
+
|
36
|
+
@opts = {
|
37
|
+
:command => nil,
|
38
|
+
:delay => 0,
|
39
|
+
:listfile => nil,
|
40
|
+
:statusfile => nil,
|
41
|
+
:verbose => false,
|
42
|
+
:debug => false
|
43
|
+
}.merge(@opts)
|
44
|
+
|
45
|
+
Carrousel::Runner.new(ARGV, @opts).run
|
data/carrousel.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'carrousel/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "carrousel"
|
8
|
+
spec.version = Carrousel::VERSION
|
9
|
+
spec.authors = ["Raj Sahae"]
|
10
|
+
spec.email = ["rajsahae@gmail.com"]
|
11
|
+
spec.description = %q{Carrousel is a robust utility designed to take a list
|
12
|
+
of generic items, and given some command, perform that command on each item
|
13
|
+
in that list. Depending on the commands return value, Carrousel will track
|
14
|
+
which items have been completed successfully, and retry items as necessary.
|
15
|
+
It will save your progress in a status database and you can quit the loop
|
16
|
+
and come back later to finish unprocessed items.}
|
17
|
+
spec.summary = %q{Robust list based action tracking utility.}
|
18
|
+
spec.homepage = "https://github.com/rajsahae/carrousel"
|
19
|
+
spec.license = "MIT"
|
20
|
+
|
21
|
+
spec.files = `git ls-files`.split($/)
|
22
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
23
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
27
|
+
spec.add_development_dependency "rake"
|
28
|
+
spec.add_development_dependency "minitest"
|
29
|
+
end
|
data/lib/carrousel.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
#!/usr/env ruby
|
2
|
+
# enconding: UTF-8
|
3
|
+
|
4
|
+
require "carrousel/version"
|
5
|
+
require 'digest'
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
##
|
9
|
+
# "Enter the Carrousel. This is the time of renewal."
|
10
|
+
#
|
11
|
+
# Carrousel is a system command execution and tracker utility.
|
12
|
+
module Carrousel
|
13
|
+
|
14
|
+
class Runner
|
15
|
+
|
16
|
+
def initialize(args, opts = {})
|
17
|
+
@args = args
|
18
|
+
@opts = opts
|
19
|
+
@incomplete = []
|
20
|
+
@complete = []
|
21
|
+
|
22
|
+
unless @opts[:listfile].nil?
|
23
|
+
lines = File.readlines(@opts[:listfile]).map(&:strip)
|
24
|
+
@incomplete.concat(lines)
|
25
|
+
end
|
26
|
+
@incomplete.concat(@args)
|
27
|
+
|
28
|
+
@opts[:statusfile] ||= generate_status_filename
|
29
|
+
open_status_file
|
30
|
+
|
31
|
+
p self if @opts[:debug]
|
32
|
+
|
33
|
+
raise ArgumentError.new("Command option is required") if @opts[:command].nil?
|
34
|
+
end # def initialize
|
35
|
+
|
36
|
+
def run
|
37
|
+
# Loop over everything in the list. Run the command. If the command fails
|
38
|
+
# then we move the item to the bottom of the list. If the command
|
39
|
+
# succeeds, we move the item to the completed list. If we are interrupted
|
40
|
+
# in the middle of processing, we ensure that the item is saved in the
|
41
|
+
# normal list, and we ensure that we write out the completed list.
|
42
|
+
until @incomplete.empty?
|
43
|
+
begin
|
44
|
+
command = [@opts[:command], @incomplete.first].join(' ')
|
45
|
+
warn "Executing command: #{command}" if @opts[:verbose]
|
46
|
+
resp = system(command)
|
47
|
+
warn "System response: #{resp}" if @opts[:verbose]
|
48
|
+
if resp
|
49
|
+
@complete << @incomplete.delete(@incomplete.first)
|
50
|
+
else
|
51
|
+
@incomplete.rotate!
|
52
|
+
end
|
53
|
+
ensure
|
54
|
+
save_status_file
|
55
|
+
end
|
56
|
+
|
57
|
+
if @opts[:delay] > 0
|
58
|
+
warn "Sleeping for #{@opts[:delay]} seconds" if @opts[:verbose]
|
59
|
+
sleep @opts[:delay]
|
60
|
+
end
|
61
|
+
end # until @incomplete.empty?
|
62
|
+
end # def run
|
63
|
+
|
64
|
+
private
|
65
|
+
def generate_status_filename
|
66
|
+
key = Digest::SHA256.hexdigest(@incomplete.sort.join).slice(0...7)
|
67
|
+
warn "status file key: #{key}" if @opts[:debug]
|
68
|
+
name = self.class.name.gsub('::', '_').downcase
|
69
|
+
File.expand_path(".#{name}_status_#{key}", Dir.pwd)
|
70
|
+
end # def generate_status_filename
|
71
|
+
|
72
|
+
private
|
73
|
+
def open_status_file
|
74
|
+
if File.exists?(@opts[:statusfile])
|
75
|
+
dbs = YAML.load(File.read(@opts[:statusfile]))
|
76
|
+
warn "opened status file:\n#{dbs}" if @opts[:debug]
|
77
|
+
if dbs
|
78
|
+
@opts[:command] ||= dbs[:command]
|
79
|
+
@complete.concat(dbs[:complete])
|
80
|
+
@incomplete.concat(dbs[:incomplete])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end # def open_status_file
|
84
|
+
|
85
|
+
private
|
86
|
+
def save_status_file
|
87
|
+
warn "Saving status file: #{@opts[:statusfile]}" if @opts[:verbose]
|
88
|
+
File.open(@opts[:statusfile], 'w') do |f|
|
89
|
+
ydb = {
|
90
|
+
:command => @opts[:command],
|
91
|
+
:complete => @complete,
|
92
|
+
:incomplete => @incomplete
|
93
|
+
}.to_yaml
|
94
|
+
f.puts(ydb)
|
95
|
+
warn "Saved status file:\n#{ydb}" if @opts[:debug]
|
96
|
+
end
|
97
|
+
true
|
98
|
+
end # def save_status_file
|
99
|
+
|
100
|
+
end # class Runner
|
101
|
+
end # module Carrousel
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: carrousel
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Raj Sahae
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: ! "Carrousel is a robust utility designed to take a list\n of generic
|
56
|
+
items, and given some command, perform that command on each item\n in that list.
|
57
|
+
Depending on the commands return value, Carrousel will track \n which items have
|
58
|
+
been completed successfully, and retry items as necessary.\n It will save your
|
59
|
+
progress in a status database and you can quit the loop \n and come back later
|
60
|
+
to finish unprocessed items."
|
61
|
+
email:
|
62
|
+
- rajsahae@gmail.com
|
63
|
+
executables:
|
64
|
+
- carrousel
|
65
|
+
extensions: []
|
66
|
+
extra_rdoc_files: []
|
67
|
+
files:
|
68
|
+
- .gitignore
|
69
|
+
- .travis.yml
|
70
|
+
- Gemfile
|
71
|
+
- LICENSE.txt
|
72
|
+
- README.md
|
73
|
+
- Rakefile
|
74
|
+
- bin/carrousel
|
75
|
+
- carrousel.gemspec
|
76
|
+
- lib/carrousel.rb
|
77
|
+
- lib/carrousel/version.rb
|
78
|
+
- test/minitest_helper.rb
|
79
|
+
- test/test_carrousel.rb
|
80
|
+
homepage: https://github.com/rajsahae/carrousel
|
81
|
+
licenses:
|
82
|
+
- MIT
|
83
|
+
metadata: {}
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ! '>='
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ! '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
requirements: []
|
99
|
+
rubyforge_project:
|
100
|
+
rubygems_version: 2.2.2
|
101
|
+
signing_key:
|
102
|
+
specification_version: 4
|
103
|
+
summary: Robust list based action tracking utility.
|
104
|
+
test_files:
|
105
|
+
- test/minitest_helper.rb
|
106
|
+
- test/test_carrousel.rb
|