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 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
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in carrousel.gemspec
4
+ gemspec
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
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ end
7
+
8
+ task :default => :test
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
@@ -0,0 +1,3 @@
1
+ module Carrousel
2
+ VERSION = "0.0.4"
3
+ end
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'carrousel'
3
+
4
+ require 'minitest/autorun'
@@ -0,0 +1,11 @@
1
+ require 'minitest_helper'
2
+
3
+ class TestCarrousel < MiniTest::Unit::TestCase
4
+ def test_that_it_has_a_version_number
5
+ refute_nil ::Carrousel::VERSION
6
+ end
7
+
8
+ def test_it_does_something_useful
9
+ assert true
10
+ end
11
+ end
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