dynosaur 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +7 -0
- data/Rakefile +0 -19
- data/lib/dynosaur/process/heroku/finder.rb +34 -0
- data/lib/dynosaur/process/heroku.rb +3 -5
- data/lib/dynosaur/process/local/finder.rb +23 -0
- data/lib/dynosaur/process/local.rb +2 -3
- data/lib/dynosaur/process.rb +8 -11
- data/lib/dynosaur/utils/os.rb +24 -0
- data/lib/dynosaur/utils/rake_command.rb +45 -0
- data/lib/dynosaur/version.rb +1 -1
- data/lib/dynosaur.rb +7 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1448d342f89404da10452e0e95176627f5c7ed56
|
4
|
+
data.tar.gz: ffe0d95b07ad64c410d89e4645289faa107c7cf5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 06a80b1d43a568785eee94acab44b02a260d4a61e83bd2502886ab2abd1dc0c2c9bf647b37b8a23ddec22a260455024a66ffd4192df89fdb7139af767387cfce
|
7
|
+
data.tar.gz: f0d630594d61500d65d7eafa207c33c36ac622d5af7f89fd63ebb0d7c6dda2649aa7ca20a1c65bcd198f92acf8bb4b4aaeaa2ad20bea3e9ff3593ffd0e18c030
|
data/README.md
CHANGED
@@ -35,6 +35,13 @@ local_process.start
|
|
35
35
|
# => 48345
|
36
36
|
```
|
37
37
|
|
38
|
+
You can also check to see if a similar rake task is already running before starting
|
39
|
+
the task (e.g. if you want at most one instance of that task running concurrently)
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
dyno = Dynosaur::Process::Heroku.new(task: 'session:destroy', args: [2500])
|
43
|
+
dyno.start unless dyno.running?
|
44
|
+
```
|
38
45
|
|
39
46
|
## Development
|
40
47
|
|
data/Rakefile
CHANGED
@@ -5,22 +5,3 @@ require 'rspec/core/rake_task'
|
|
5
5
|
RSpec::Core::RakeTask.new(:spec)
|
6
6
|
|
7
7
|
task default: :spec
|
8
|
-
|
9
|
-
task :echo, [:arg1, :arg2] do |_task, args|
|
10
|
-
puts %Q(ARG1: "#{args[:arg1]}")
|
11
|
-
puts %Q(ARG2: "#{args[:arg2]}")
|
12
|
-
end
|
13
|
-
|
14
|
-
task :sleep, [:duration] do |_task, args|
|
15
|
-
File.open('/tmp/sleep', 'w') do |file|
|
16
|
-
file.puts "Sleeping"
|
17
|
-
args[:duration].to_i.times do
|
18
|
-
sleep(1)
|
19
|
-
file.print('.')
|
20
|
-
file.flush
|
21
|
-
end
|
22
|
-
file.print("\n")
|
23
|
-
file.puts "Awake"
|
24
|
-
file.flush
|
25
|
-
end
|
26
|
-
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Detects if a running dyno is currently executing the rake command
|
2
|
+
module Dynosaur
|
3
|
+
class Process
|
4
|
+
class Heroku
|
5
|
+
class Finder
|
6
|
+
def initialize(rake_command:, client: Client::HerokuClient.client)
|
7
|
+
@rake_command = rake_command
|
8
|
+
@client = client
|
9
|
+
end
|
10
|
+
|
11
|
+
def exists?
|
12
|
+
one_off_dynos.any? do |dyno|
|
13
|
+
Utils::RakeCommand.valid?(dyno.command) &&
|
14
|
+
Utils::RakeCommand.parse(dyno.command) == rake_command
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :rake_command, :client
|
21
|
+
|
22
|
+
# @return [Array] Object instances, which respond to #command, for all
|
23
|
+
# locally one off dynos
|
24
|
+
def one_off_dynos
|
25
|
+
app_name = Dynosaur::Client::HerokuClient.app_name
|
26
|
+
dynos = client.dyno.list(app_name).map do |response|
|
27
|
+
Struct.new(:type, :command).new(response['type'], response['command'])
|
28
|
+
end
|
29
|
+
dynos.select { |dyno| dyno.type == 'run' }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
require 'dynosaur/client/heroku_client'
|
2
2
|
|
3
|
-
require_relative '../process'
|
4
|
-
|
5
3
|
# Start a detached rake task on a one-off dyno
|
6
4
|
module Dynosaur
|
7
5
|
class Process
|
@@ -23,10 +21,10 @@ module Dynosaur
|
|
23
21
|
|
24
22
|
def start
|
25
23
|
app_name = Dynosaur::Client::HerokuClient.app_name
|
26
|
-
|
27
|
-
create_opts = { command: rake_command, attach: false }
|
24
|
+
client = Dynosaur::Client::HerokuClient.client
|
25
|
+
create_opts = { command: rake_command.to_s, attach: false }
|
28
26
|
create_opts[:size] = size if size
|
29
|
-
response =
|
27
|
+
response = client.dyno.create(app_name, create_opts)
|
30
28
|
response['name']
|
31
29
|
end
|
32
30
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Detects if a running process is currently executing the rake command
|
2
|
+
module Dynosaur
|
3
|
+
class Process
|
4
|
+
class Local
|
5
|
+
class Finder
|
6
|
+
def initialize(rake_command:)
|
7
|
+
@rake_command = rake_command
|
8
|
+
end
|
9
|
+
|
10
|
+
def exists?
|
11
|
+
Utils::OS.structured_ps.any? do |process|
|
12
|
+
Utils::RakeCommand.valid?(process.command) &&
|
13
|
+
Utils::RakeCommand.parse(process.command) == rake_command
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :rake_command
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,10 +1,9 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# Start the rake task in a local process
|
3
2
|
module Dynosaur
|
4
3
|
class Process
|
5
4
|
class Local < Process
|
6
5
|
def start
|
7
|
-
pid = ::Process.spawn(rake_command)
|
6
|
+
pid = ::Process.spawn(rake_command.to_s)
|
8
7
|
::Process.detach(pid)
|
9
8
|
pid
|
10
9
|
end
|
data/lib/dynosaur/process.rb
CHANGED
@@ -3,29 +3,26 @@ require 'shellwords'
|
|
3
3
|
module Dynosaur
|
4
4
|
class Process
|
5
5
|
def initialize(task:, args: [], opts: {})
|
6
|
-
@
|
7
|
-
@args = args
|
6
|
+
@rake_command = Utils::RakeCommand.new(task: task, args: args)
|
8
7
|
after_initialize(opts)
|
9
8
|
end
|
10
9
|
|
10
|
+
def running?
|
11
|
+
klass = self.class.const_get('Finder')
|
12
|
+
finder = klass.new(rake_command: rake_command)
|
13
|
+
finder.exists?
|
14
|
+
end
|
15
|
+
|
11
16
|
def start
|
12
17
|
fail NotImplementedError, 'This method must be implemented in a subclass'
|
13
18
|
end
|
14
19
|
|
15
20
|
private
|
16
21
|
|
17
|
-
attr_reader :
|
22
|
+
attr_reader :rake_command
|
18
23
|
|
19
24
|
def after_initialize(opts)
|
20
25
|
# Do nothing so subclasses don't have to override if they want a no-op
|
21
26
|
end
|
22
|
-
|
23
|
-
def rake_command
|
24
|
-
formatted_args = args.map do |arg|
|
25
|
-
arg.is_a?(String) ? arg.shellescape : arg
|
26
|
-
end.join(',')
|
27
|
-
task_with_args = args.empty? ? task : "#{task}[#{formatted_args}]"
|
28
|
-
"rake #{task_with_args} --trace"
|
29
|
-
end
|
30
27
|
end
|
31
28
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Utility methods for interacting with the underlying OS
|
2
|
+
module Dynosaur
|
3
|
+
module Utils
|
4
|
+
module OS
|
5
|
+
class << self
|
6
|
+
# @return [Array] Object instances, which respond to #command, for all
|
7
|
+
# locally running processes returned by the ps command
|
8
|
+
def structured_ps
|
9
|
+
ps_array = command_ps.split("\n").map(&:strip)
|
10
|
+
ps_array.shift # Remove the header row
|
11
|
+
ps_array.map do |command|
|
12
|
+
Struct.new(:command).new(command)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def command_ps
|
19
|
+
`ps -o command`
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# Utility methods for generating and parsing rake command
|
2
|
+
module Dynosaur
|
3
|
+
module Utils
|
4
|
+
class RakeCommand
|
5
|
+
PARSE_REGEX = /\brake\s+([\w:]+)(\[.*\])?/
|
6
|
+
|
7
|
+
attr_reader :task, :args
|
8
|
+
|
9
|
+
# @param command [String] the command to test for validity
|
10
|
+
# @return [true|false] true iff the string is a valid rake command
|
11
|
+
def self.valid?(command)
|
12
|
+
!(command =~ PARSE_REGEX).nil?
|
13
|
+
end
|
14
|
+
|
15
|
+
# @param command [String] the command to parse
|
16
|
+
# @return [RakeCommand] an instance that represents the command being parsed
|
17
|
+
# @raise [ArgumentError] if the command is not a valid rake command
|
18
|
+
def self.parse(command)
|
19
|
+
match = command.match(PARSE_REGEX)
|
20
|
+
raise ArgumentError, %Q(Invalid rake command: "#{command}") unless match
|
21
|
+
task = match[1]
|
22
|
+
args = match[2] ? match[2].tr('[]', '').split(',') : []
|
23
|
+
new(task: task, args: args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(task:, args: [])
|
27
|
+
@task = task
|
28
|
+
@args = args
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [String] the full rake command, including arguments
|
32
|
+
def to_s
|
33
|
+
formatted_args = args.map do |arg|
|
34
|
+
arg.is_a?(String) ? arg.shellescape : arg
|
35
|
+
end.join(',')
|
36
|
+
task_with_args = args.empty? ? task : "#{task}[#{formatted_args}]"
|
37
|
+
"rake #{task_with_args} --trace"
|
38
|
+
end
|
39
|
+
|
40
|
+
def ==(other)
|
41
|
+
task == other.task && args.map(&:to_s) == other.args.map(&:to_s)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/dynosaur/version.rb
CHANGED
data/lib/dynosaur.rb
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
require 'dynosaur/version'
|
2
|
+
|
3
|
+
require 'dynosaur/process'
|
2
4
|
require 'dynosaur/process/heroku'
|
5
|
+
require 'dynosaur/process/heroku/finder'
|
3
6
|
require 'dynosaur/process/local'
|
7
|
+
require 'dynosaur/process/local/finder'
|
8
|
+
|
9
|
+
require 'dynosaur/utils/os'
|
10
|
+
require 'dynosaur/utils/rake_command'
|
4
11
|
|
5
12
|
# Spin up a rake task in a separate process
|
6
13
|
module Dynosaur
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dynosaur
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Collier
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: platform-api
|
@@ -117,7 +117,11 @@ files:
|
|
117
117
|
- lib/dynosaur/client/heroku_client.rb
|
118
118
|
- lib/dynosaur/process.rb
|
119
119
|
- lib/dynosaur/process/heroku.rb
|
120
|
+
- lib/dynosaur/process/heroku/finder.rb
|
120
121
|
- lib/dynosaur/process/local.rb
|
122
|
+
- lib/dynosaur/process/local/finder.rb
|
123
|
+
- lib/dynosaur/utils/os.rb
|
124
|
+
- lib/dynosaur/utils/rake_command.rb
|
121
125
|
- lib/dynosaur/version.rb
|
122
126
|
homepage:
|
123
127
|
licenses:
|