dronejob 1.0.8 → 1.0.9
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 +4 -4
- data/Gemfile.lock +7 -1
- data/dronejob.gemspec +1 -0
- data/lib/dronejob/base.rb +2 -0
- data/lib/dronejob/command.rb +3 -15
- data/lib/dronejob/modules/core.rb +30 -18
- data/lib/dronejob/modules/params.rb +21 -1
- data/lib/dronejob/modules/phases.rb +7 -3
- data/lib/dronejob/modules/queue.rb +9 -3
- data/lib/dronejob/modules/stateful.rb +18 -0
- data/lib/dronejob/modules/workspace.rb +26 -0
- data/lib/dronejob/version.rb +1 -1
- data/lib/dronejob/workspace_dir/archive.rb +18 -0
- data/lib/dronejob/workspace_dir.rb +23 -16
- data/lib/dronejob/workspace_file/archive.rb +47 -0
- data/lib/dronejob/workspace_file/media.rb +81 -0
- data/lib/dronejob/workspace_file/net.rb +33 -0
- data/lib/dronejob/workspace_file/parse.rb +38 -0
- data/lib/dronejob/workspace_file.rb +47 -90
- metadata +22 -3
- data/lib/dronejob/one_off.rb +0 -77
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f9dbb72f363b027c7375e6d4c0c3ac4944e210df
|
4
|
+
data.tar.gz: 1fc73ad750f50c725ecc8472ccab543c6de62842
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c3809dd877e6ced5dd54a528e9f39580201884610dd8fe577ef345d53e2809097a09ee8a3dcb0acd6cc9331740b3434e5704efd0cb2538051a45674564f9b85
|
7
|
+
data.tar.gz: 21c53828b64f5fec596b8f0c487181b81731cd3b25fe2b7c4e2772fff3729b96065ea7a9829a14090b8c8d32988648bd7e23923f31783d2f7bfa2b3113f1457b
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
dronejob (1.0.
|
4
|
+
dronejob (1.0.9)
|
5
5
|
activejob (~> 4.2)
|
6
6
|
bundler (~> 1.11)
|
7
7
|
git (~> 1.2)
|
@@ -12,6 +12,7 @@ PATH
|
|
12
12
|
sidekiq (~> 4.1.0)
|
13
13
|
sidekiq-status (~> 0.6.0)
|
14
14
|
thor (~> 0.19)
|
15
|
+
typhoeus (~> 1.0)
|
15
16
|
|
16
17
|
GEM
|
17
18
|
remote: http://rubygems.org/
|
@@ -29,6 +30,9 @@ GEM
|
|
29
30
|
concurrent-ruby (1.0.1)
|
30
31
|
connection_pool (2.2.0)
|
31
32
|
diff-lcs (1.2.5)
|
33
|
+
ethon (0.9.0)
|
34
|
+
ffi (>= 1.3.0)
|
35
|
+
ffi (1.9.10)
|
32
36
|
git (1.3.0)
|
33
37
|
globalid (0.3.6)
|
34
38
|
activesupport (>= 4.1.0)
|
@@ -69,6 +73,8 @@ GEM
|
|
69
73
|
thor (0.19.1)
|
70
74
|
thread_safe (0.3.5)
|
71
75
|
tilt (2.0.2)
|
76
|
+
typhoeus (1.0.2)
|
77
|
+
ethon (>= 0.9.0)
|
72
78
|
tzinfo (1.2.2)
|
73
79
|
thread_safe (~> 0.1)
|
74
80
|
|
data/dronejob.gemspec
CHANGED
@@ -24,6 +24,7 @@ Gem::Specification.new do |s|
|
|
24
24
|
s.add_runtime_dependency "open_uri_redirections", "~> 0.2"
|
25
25
|
s.add_runtime_dependency "rubyzip", "~> 1.1"
|
26
26
|
s.add_runtime_dependency "activejob", "~> 4.2"
|
27
|
+
s.add_runtime_dependency "typhoeus", "~> 1.0"
|
27
28
|
s.add_development_dependency "rspec", "~> 3.3"
|
28
29
|
s.add_development_dependency "pry", "~> 0.10"
|
29
30
|
s.files = `git ls-files`.split("\n")
|
data/lib/dronejob/base.rb
CHANGED
@@ -7,6 +7,7 @@ require 'dronejob/modules/queue'
|
|
7
7
|
require 'dronejob/modules/options'
|
8
8
|
require 'dronejob/modules/params'
|
9
9
|
require 'dronejob/modules/phases'
|
10
|
+
require 'dronejob/modules/stateful'
|
10
11
|
require 'dronejob/modules/workspace'
|
11
12
|
|
12
13
|
module Dronejob
|
@@ -21,6 +22,7 @@ module Dronejob
|
|
21
22
|
include Modules::Options
|
22
23
|
include Modules::Params
|
23
24
|
include Modules::Phases
|
25
|
+
include Modules::Stateful
|
24
26
|
include Modules::Workspace
|
25
27
|
|
26
28
|
ActiveSupport.run_load_hooks(:dronejob, self)
|
data/lib/dronejob/command.rb
CHANGED
@@ -21,7 +21,7 @@ module Dronejob
|
|
21
21
|
|
22
22
|
# Worker options
|
23
23
|
worker.params.each do |key, config|
|
24
|
-
method_option(key, required: config[:required], type: config[:
|
24
|
+
method_option(key, required: config[:required], type: config[:argument_type], default: config[:default])
|
25
25
|
end
|
26
26
|
|
27
27
|
define_method(identifier) do
|
@@ -59,18 +59,6 @@ module Dronejob
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
Dronejob::Loader.workers(:one_off).each do |identifier, worker|
|
63
|
-
desc identifier, "Run #{identifier} one-off worker"
|
64
|
-
method_option(:break, aliases: "-b", type: :boolean, default: false)
|
65
|
-
method_option(:skip, aliases: "-s", type: :array, default: [])
|
66
|
-
worker.params.each do |key, config|
|
67
|
-
method_option(key, required: config[:required], type: config[:type], default: config[:default])
|
68
|
-
end
|
69
|
-
define_method(identifier) do
|
70
|
-
worker.new.perform(options)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
62
|
desc :server, "Start Dronejob Server"
|
75
63
|
method_option(:queue_adapter, type: :string, default: "sidekiq", enum: ["sidekiq"])
|
76
64
|
method_option(:jobs_path, type: :string)
|
@@ -95,7 +83,7 @@ module Dronejob
|
|
95
83
|
Dronejob::Base.log("info", "Archiving #{dir.name}")
|
96
84
|
archive_file = archive_dir.file("#{dir.name}.zip")
|
97
85
|
if archive_file.exists? and !options.force
|
98
|
-
Dronejob::Base.log("error", "Error: Archive '#{archive_file
|
86
|
+
Dronejob::Base.log("error", "Error: Archive '#{archive_file}' already exists. Use --force to replace.")
|
99
87
|
else
|
100
88
|
archive_file.delete! if archive_file.exists?
|
101
89
|
dir.compress(archive_file)
|
@@ -113,7 +101,7 @@ module Dronejob
|
|
113
101
|
def unarchive
|
114
102
|
archives_dir = WorkspaceDir.new("archive")
|
115
103
|
archive_file = archives_dir.file("#{options.archive}.zip")
|
116
|
-
Dronejob::Base.log("info", "Unarchiving '#{archive_file
|
104
|
+
Dronejob::Base.log("info", "Unarchiving '#{archive_file}'")
|
117
105
|
target_dir = WorkspaceDir.new("tmp/jobs").dir(options.archive)
|
118
106
|
if !options.force and target_dir.exists?
|
119
107
|
Dronejob::Base.log("error", "Error: Job directory already exists")
|
@@ -8,45 +8,57 @@ module Dronejob
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def perform(params)
|
11
|
-
|
11
|
+
set_parameters(params)
|
12
12
|
validate_parameters!
|
13
13
|
create_working_dir
|
14
|
-
load_variables
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
15
|
+
if self.class.stateful?
|
16
|
+
load_variables
|
17
|
+
git_init(@working_dir.to_s)
|
18
|
+
git_collect_commits
|
19
|
+
git_commit("start")
|
20
|
+
if param(:from)
|
21
|
+
info("starting from phase #{param(:from)}")
|
22
|
+
phase = prev_phase(param(:from))
|
23
|
+
raise("phase '#{param(:from)}' not found!") if phase.nil? or @commits[phase.to_s].nil?
|
24
|
+
git_reset(phase.to_s)
|
25
|
+
else
|
26
|
+
git_reset
|
27
|
+
end
|
28
|
+
git_collect_commits
|
29
|
+
git_clean
|
26
30
|
end
|
27
|
-
git_collect_commits
|
28
|
-
git_clean
|
29
31
|
|
30
32
|
# Run through phases
|
31
|
-
each_phase do |phase,
|
33
|
+
each_phase do |phase, phase_config|
|
32
34
|
begin
|
33
35
|
phase_result = public_send(phase)
|
34
36
|
rescue Exception => e
|
35
37
|
error(e.message)
|
36
38
|
error(e.backtrace.join("\n"))
|
39
|
+
delete_working_dir if self.class.cleanup_on_error?
|
40
|
+
publish_status({title: self.title, description: e.message, phase: phase, backtrace: e.backtrace}, "failed") if param(:notify) and !param(:run)
|
37
41
|
return false
|
38
42
|
end
|
39
|
-
|
40
|
-
|
43
|
+
|
44
|
+
publish_status({title: self.title, description: phase_config[:title], phase: phase}, "working") if phase_config[:notify] and param(:notify) and !param(:run)
|
45
|
+
git_commit(phase) if self.class.stateful?
|
41
46
|
end
|
42
47
|
@phase = "complete"
|
43
|
-
|
48
|
+
|
49
|
+
publish_status({title: self.title, description: "Job Completed!", phase: @phase}, "complete") if param(:notify) and !param(:run)
|
50
|
+
|
51
|
+
delete_working_dir if self.class.cleanup_on_complete?
|
44
52
|
end
|
45
53
|
|
46
54
|
def uuid
|
47
55
|
@uuid ||= "#{self.class.name.split('::').last.underscore}_#{SecureRandom.uuid}"
|
48
56
|
end
|
49
57
|
|
58
|
+
def title
|
59
|
+
self.class.name
|
60
|
+
end
|
61
|
+
|
50
62
|
def shell
|
51
63
|
@shell ||= Thor::Shell::Color.new
|
52
64
|
end
|
@@ -7,6 +7,14 @@ module Dronejob
|
|
7
7
|
def param(key, options)
|
8
8
|
@params ||= {}
|
9
9
|
@params[key] = options
|
10
|
+
@params[key][:argument_type] = @params[key][:type]
|
11
|
+
if @params[key][:type] == :base64 or @params[key][:type] == :json64
|
12
|
+
@params[key][:argument_type] = :string
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def param_config(key)
|
17
|
+
@params[key.to_sym]
|
10
18
|
end
|
11
19
|
|
12
20
|
def params
|
@@ -14,6 +22,18 @@ module Dronejob
|
|
14
22
|
end
|
15
23
|
end
|
16
24
|
|
25
|
+
def set_parameters(params)
|
26
|
+
@params = params.map{|name, value| [name, transform_parameter(name, value)]}.to_h
|
27
|
+
end
|
28
|
+
|
29
|
+
def transform_parameter(name, value)
|
30
|
+
if config = self.class.param_config(name)
|
31
|
+
return Base64.strict_decode64(value) if config[:type] == :base64
|
32
|
+
return JSON.parse(Base64.strict_decode64(value)) if config[:type] == :json64
|
33
|
+
end
|
34
|
+
value
|
35
|
+
end
|
36
|
+
|
17
37
|
def param(key)
|
18
38
|
@params ||= {}
|
19
39
|
@params[key.to_s]
|
@@ -29,7 +49,7 @@ module Dronejob
|
|
29
49
|
end
|
30
50
|
|
31
51
|
# Validate parameters
|
32
|
-
type_map = {string: [String], numeric: [Fixnum, Integer, Float], array: [Array], boolean: [TrueClass, FalseClass]}
|
52
|
+
type_map = {string: [String], numeric: [Fixnum, Integer, Float], array: [Array], boolean: [TrueClass, FalseClass], base64: [String], json64: [Hash, Array]}
|
33
53
|
self.class.params.each do |param_name, param_config|
|
34
54
|
param_value = @params[param_name.to_s]
|
35
55
|
if param_value.nil?
|
@@ -30,6 +30,7 @@ module Dronejob
|
|
30
30
|
elsif skip_phase?(phase)
|
31
31
|
info("skipping...")
|
32
32
|
else
|
33
|
+
info "running phase #{phase}"
|
33
34
|
# Require libraries
|
34
35
|
if !config[:require].nil?
|
35
36
|
config[:require].each do |library|
|
@@ -54,12 +55,15 @@ module Dronejob
|
|
54
55
|
end
|
55
56
|
|
56
57
|
@dronejob_completed = true
|
57
|
-
git_commit("dronejob_completed")
|
58
|
-
info("JOB COMPLETED")
|
58
|
+
git_commit("dronejob_completed") if self.class.stateful?
|
59
59
|
end
|
60
60
|
|
61
61
|
def completed_phase?(phase)
|
62
|
-
|
62
|
+
if self.class.stateful?
|
63
|
+
@commits.include?(phase.to_s)
|
64
|
+
else
|
65
|
+
false
|
66
|
+
end
|
63
67
|
end
|
64
68
|
|
65
69
|
def skip_phase?(phase)
|
@@ -18,9 +18,15 @@ module Dronejob
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
def publish_status(
|
22
|
-
data =
|
23
|
-
|
21
|
+
def publish_status(data={}, status="working", backend=false)
|
22
|
+
data[:action] = "update_process"
|
23
|
+
data[:user_id] = param(:user_id)
|
24
|
+
data[:jid] = job_id
|
25
|
+
data[:worker] = Loader.identifier_for(self)
|
26
|
+
data[:timestamp] = Time.now.to_i
|
27
|
+
data[:status] = status
|
28
|
+
data[:secret_key] = option(:secret_key) if backend
|
29
|
+
Redis.new(url: option(:redis_url)).publish("processes_#{backend ? 'backend' : data[:user_id]}", data.to_json)
|
24
30
|
end
|
25
31
|
|
26
32
|
def publish_channel
|
@@ -5,6 +5,24 @@ module Dronejob
|
|
5
5
|
module Workspace
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
|
+
module ClassMethods
|
9
|
+
def cleanup_on_complete(value=true)
|
10
|
+
@cleanup_on_complete = value
|
11
|
+
end
|
12
|
+
|
13
|
+
def cleanup_on_complete?
|
14
|
+
!!@cleanup_on_complete
|
15
|
+
end
|
16
|
+
|
17
|
+
def cleanup_on_error(value=true)
|
18
|
+
@cleanup_on_error = value
|
19
|
+
end
|
20
|
+
|
21
|
+
def cleanup_on_error?
|
22
|
+
!!@cleanup_on_error
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
8
26
|
included do
|
9
27
|
attr_accessor :working_dir
|
10
28
|
cattr_accessor(:jobs_path) { "app/jobs" }
|
@@ -30,9 +48,17 @@ module Dronejob
|
|
30
48
|
@working_dir
|
31
49
|
end
|
32
50
|
|
51
|
+
def delete_working_dir
|
52
|
+
working_dir.delete!
|
53
|
+
end
|
54
|
+
|
33
55
|
def asset_file(path)
|
34
56
|
WorkspaceDir.new("app/assets").file(path)
|
35
57
|
end
|
58
|
+
|
59
|
+
def asset_dir(path)
|
60
|
+
WorkspaceDir.new("app/assets").dir(path)
|
61
|
+
end
|
36
62
|
end
|
37
63
|
end
|
38
64
|
end
|
data/lib/dronejob/version.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Dronejob
|
2
|
+
class WorkspaceDir
|
3
|
+
module Archive
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def compress(target_file)
|
7
|
+
target_file.delete!
|
8
|
+
require "zip"
|
9
|
+
Zip::File.open(target_file.to_s, 'w') do |zipfile|
|
10
|
+
Dir["#{to_s}/**/**"].each do |file|
|
11
|
+
zipfile.add(file.sub("#{to_s}/",''), file)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
self
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,5 +1,9 @@
|
|
1
|
+
require 'dronejob/workspace_dir/archive'
|
2
|
+
|
1
3
|
module Dronejob
|
2
4
|
class WorkspaceDir
|
5
|
+
include WorkspaceDir::Archive
|
6
|
+
|
3
7
|
attr_accessor :workspace, :path
|
4
8
|
|
5
9
|
def initialize(workspace, path="")
|
@@ -7,25 +11,30 @@ module Dronejob
|
|
7
11
|
@path = path
|
8
12
|
end
|
9
13
|
|
10
|
-
def
|
11
|
-
File.
|
14
|
+
def to_s
|
15
|
+
File.join(@workspace, @path)
|
12
16
|
end
|
13
17
|
|
14
|
-
def
|
15
|
-
File.
|
18
|
+
def name
|
19
|
+
File.basename(to_s)
|
16
20
|
end
|
17
21
|
|
18
22
|
def create
|
19
|
-
FileUtils.mkdir_p(
|
23
|
+
FileUtils.mkdir_p(to_s)
|
20
24
|
self
|
21
25
|
end
|
22
26
|
|
23
27
|
def exists?
|
24
|
-
File.directory?(
|
28
|
+
File.directory?(to_s)
|
29
|
+
end
|
30
|
+
|
31
|
+
def copy(target_dir)
|
32
|
+
target_dir.parent_dir.create if !target_dir.parent_dir.exists?
|
33
|
+
FileUtils.cp_r(to_s, target_dir.to_s)
|
25
34
|
end
|
26
35
|
|
27
36
|
def delete!
|
28
|
-
FileUtils.rm_rf(
|
37
|
+
FileUtils.rm_rf(to_s)
|
29
38
|
end
|
30
39
|
|
31
40
|
def file(file_path)
|
@@ -36,19 +45,17 @@ module Dronejob
|
|
36
45
|
WorkspaceDir.new(@workspace, File.join(@path, dir_path))
|
37
46
|
end
|
38
47
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
46
|
-
self
|
48
|
+
def root_dir
|
49
|
+
WorkspaceDir.new(@workspace, "")
|
50
|
+
end
|
51
|
+
|
52
|
+
def parent_dir
|
53
|
+
root_dir.dir(File.expand_path("..", @path))
|
47
54
|
end
|
48
55
|
|
49
56
|
def children
|
50
57
|
entries = []
|
51
|
-
Dir.chdir(
|
58
|
+
Dir.chdir(to_s) do
|
52
59
|
Dir["*"].each do |path|
|
53
60
|
entries.push(dir(path))
|
54
61
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Dronejob
|
2
|
+
class WorkspaceFile
|
3
|
+
module Archive
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
|
7
|
+
def extract(target_dir)
|
8
|
+
target_dir.create
|
9
|
+
if extension == "zip"
|
10
|
+
extract_zip(target_dir)
|
11
|
+
elsif extension == "gz"
|
12
|
+
extract_gz(target_dir)
|
13
|
+
end
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def extract_zip(target_dir)
|
20
|
+
require "zip"
|
21
|
+
Zip::File.open(to_s) do |archive|
|
22
|
+
archive.each do |entry|
|
23
|
+
entry.extract(File.join(target_dir.to_s, entry.name))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def extract_gz(target_dir)
|
29
|
+
require 'rubygems/package'
|
30
|
+
workspace_dir = target_dir.root_dir
|
31
|
+
archive = Gem::Package::TarReader.new(Zlib::GzipReader.open(to_s))
|
32
|
+
archive.rewind
|
33
|
+
archive.each do |entry|
|
34
|
+
if entry.directory?
|
35
|
+
archive_dir = workspace_dir.dir(entry.full_name)
|
36
|
+
archive_dir.create
|
37
|
+
elsif entry.file?
|
38
|
+
archive_file = workspace_dir.file(entry.full_name)
|
39
|
+
archive_file.write(entry.read)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
archive.close
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Dronejob
|
2
|
+
class WorkspaceFile
|
3
|
+
module Media
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def acbaker(type, output_dir, delete=true)
|
7
|
+
require "acbaker"
|
8
|
+
output_dir.delete! if delete and output_dir.exists?
|
9
|
+
output_dir.create
|
10
|
+
config = WorkspaceDir.new("app/assets").file("acbaker/#{type}.json").read_json
|
11
|
+
acb = Acbaker::AssetPack.new(type, json: config)
|
12
|
+
acb.process(to_s, output_dir.to_s)
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def image?
|
17
|
+
["jpg", "jpeg", "gif", "png"].include?(extension)
|
18
|
+
end
|
19
|
+
|
20
|
+
def video?
|
21
|
+
["mp4"].include?(extension)
|
22
|
+
end
|
23
|
+
|
24
|
+
def audio?
|
25
|
+
["mp3"].include?(extension)
|
26
|
+
end
|
27
|
+
|
28
|
+
def cache_assets(cache_dir, &block)
|
29
|
+
hydra = Typhoeus::Hydra.new(max_concurrency: 10)
|
30
|
+
html = contents
|
31
|
+
html.scan(/["'(]{1}(https?\:\/\/[^"')]+\.(jpg|jpeg|png|gif|mp3|mp4))["')?#]{1}/).map{|match| match[0]}.uniq.each do |url|
|
32
|
+
ext = File.extname(url).gsub(/^\./, "")
|
33
|
+
cache_file = cache_dir.file("#{Digest::MD5.hexdigest(url)}.#{ext}")
|
34
|
+
request = cache_file.queue_download(url) do
|
35
|
+
cache_file.optimize!
|
36
|
+
html.gsub!(url, cache_file.relative_path)
|
37
|
+
end
|
38
|
+
hydra.queue(request)
|
39
|
+
end
|
40
|
+
hydra.run
|
41
|
+
set(html)
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def optimize!
|
46
|
+
return false if !exists?
|
47
|
+
return optimize_jpg! if image? and ["jpg", "jpeg"].include?(extension)
|
48
|
+
return optimize_png! if image? and ["png"].include?(extension)
|
49
|
+
false
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def optimize_jpg!
|
55
|
+
require "rmagick"
|
56
|
+
image_max_width = Dronejob::Base.option(:image_max_width)
|
57
|
+
image = Magick::Image.read(to_s).first
|
58
|
+
image.change_geometry!("#{image_max_width}>x"){|cols, rows, img| img.resize!(cols, rows)} if image.columns > image_max_width
|
59
|
+
image.write(to_s) { self.quality = Dronejob::Base.option(:image_quality) }
|
60
|
+
image.destroy!
|
61
|
+
end
|
62
|
+
|
63
|
+
def optimize_png!
|
64
|
+
require "rmagick"
|
65
|
+
image_max_width = Dronejob::Base.option(:image_max_width)
|
66
|
+
image = Magick::Image.read(to_s).first
|
67
|
+
image.change_geometry!("#{image_max_width}>x"){|cols, rows, img| img.resize!(cols, rows)} if image.columns > image_max_width
|
68
|
+
|
69
|
+
# Convert to jpg
|
70
|
+
if !image.alpha? or image.resize(1,1).pixel_color(0,0).opacity == 0
|
71
|
+
image.format = "JPG"
|
72
|
+
rename!("#{basename}.jpg")
|
73
|
+
end
|
74
|
+
|
75
|
+
image.write(to_s) { self.quality = Dronejob::Base.option(:image_quality) }
|
76
|
+
image.destroy!
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "typhoeus"
|
2
|
+
require "open-uri"
|
3
|
+
require "open_uri_redirections"
|
4
|
+
|
5
|
+
module Dronejob
|
6
|
+
class WorkspaceFile
|
7
|
+
module Net
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
def cdn_download(key)
|
11
|
+
download("http://#{Dronejob::Base.option(:cdn_bucket)}/#{key}")
|
12
|
+
end
|
13
|
+
|
14
|
+
def queue_download(url, &block)
|
15
|
+
request = Typhoeus::Request.new(url)
|
16
|
+
request.on_complete do |response|
|
17
|
+
if response.success?
|
18
|
+
write(response.body)
|
19
|
+
block.call(self) if !block.nil?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
request
|
23
|
+
end
|
24
|
+
|
25
|
+
def download(url)
|
26
|
+
contents = open(url, { ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE, allow_redirections: :safe }).read
|
27
|
+
dir.create if !dir.exists?
|
28
|
+
write(contents)
|
29
|
+
self
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Dronejob
|
2
|
+
class WorkspaceFile
|
3
|
+
module Parse
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def pbxproj_replace(data)
|
7
|
+
data.each do |key, value|
|
8
|
+
replace(/#{key} = .*;/, "#{key} = \"#{value}\";") if !value.nil?
|
9
|
+
end
|
10
|
+
write
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def with_plist(&block)
|
15
|
+
require "plist"
|
16
|
+
plist = Plist.parse_xml(to_s)
|
17
|
+
block.call(plist)
|
18
|
+
write(Plist::Emit.dump(plist))
|
19
|
+
end
|
20
|
+
|
21
|
+
def read_json
|
22
|
+
JSON.parse(read)
|
23
|
+
end
|
24
|
+
|
25
|
+
def read_yaml
|
26
|
+
require "psych"
|
27
|
+
Psych.load_file(to_s)
|
28
|
+
end
|
29
|
+
|
30
|
+
def read_haml(options)
|
31
|
+
require "haml"
|
32
|
+
engine = Haml::Engine.new(read)
|
33
|
+
engine.render(Object.new, options)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -1,9 +1,15 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
1
|
+
require 'dronejob/workspace_file/archive'
|
2
|
+
require 'dronejob/workspace_file/media'
|
3
|
+
require 'dronejob/workspace_file/net'
|
4
|
+
require 'dronejob/workspace_file/parse'
|
5
|
+
|
5
6
|
module Dronejob
|
6
7
|
class WorkspaceFile
|
8
|
+
include WorkspaceFile::Archive
|
9
|
+
include WorkspaceFile::Media
|
10
|
+
include WorkspaceFile::Net
|
11
|
+
include WorkspaceFile::Parse
|
12
|
+
|
7
13
|
attr_accessor :workspace, :path
|
8
14
|
|
9
15
|
def initialize(workspace, path)
|
@@ -11,116 +17,67 @@ module Dronejob
|
|
11
17
|
@path = path
|
12
18
|
end
|
13
19
|
|
14
|
-
def set(
|
15
|
-
@contents =
|
20
|
+
def set(data)
|
21
|
+
@contents = data
|
16
22
|
self
|
17
23
|
end
|
18
|
-
|
24
|
+
|
19
25
|
def contents
|
20
26
|
@contents ||= read
|
21
27
|
end
|
22
|
-
|
28
|
+
|
23
29
|
def replace(key, value)
|
24
30
|
contents.gsub!(key, value)
|
25
31
|
self
|
26
32
|
end
|
27
33
|
|
28
|
-
def
|
29
|
-
data
|
30
|
-
|
31
|
-
|
32
|
-
end
|
33
|
-
|
34
|
-
def with_plist(&block)
|
35
|
-
require "plist"
|
36
|
-
plist = Plist.parse_xml(full_path)
|
37
|
-
block.call(plist)
|
38
|
-
write(Plist::Emit.dump(plist))
|
39
|
-
end
|
40
|
-
|
41
|
-
def write(contents=nil)
|
42
|
-
contents ||= @contents
|
43
|
-
File.open(full_path, "wb") do |file|
|
44
|
-
file << contents
|
45
|
-
end
|
34
|
+
def write(data=nil)
|
35
|
+
data ||= @contents
|
36
|
+
dir.create if !dir.exists?
|
37
|
+
File.open(to_s, "wb") {|file| file << data}
|
46
38
|
self
|
47
39
|
end
|
48
40
|
|
49
|
-
def
|
41
|
+
def copy(target_file)
|
42
|
+
target_file.dir.create if !target_file.dir.exists?
|
43
|
+
FileUtils.cp(to_s, target_file.to_s)
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_s
|
50
47
|
File.join(@workspace, @path)
|
51
48
|
end
|
52
|
-
|
49
|
+
|
50
|
+
def relative_path
|
51
|
+
@path.gsub(/^\//, "")
|
52
|
+
end
|
53
|
+
|
53
54
|
def exists?
|
54
|
-
File.exists?(
|
55
|
+
File.exists?(to_s)
|
55
56
|
end
|
56
|
-
|
57
|
+
|
57
58
|
def read
|
58
|
-
File.open(
|
59
|
-
end
|
60
|
-
|
61
|
-
def read_json
|
62
|
-
JSON.parse(read)
|
63
|
-
end
|
64
|
-
|
65
|
-
def read_yaml
|
66
|
-
Psych.load_file(full_path)
|
67
|
-
end
|
68
|
-
|
69
|
-
def read_haml(options)
|
70
|
-
require "haml"
|
71
|
-
engine = Haml::Engine.new(read)
|
72
|
-
engine.render(Object.new, options)
|
73
|
-
end
|
74
|
-
|
75
|
-
def download!(url)
|
76
|
-
raise "file not found at #{url}" unless download(url)
|
77
|
-
self
|
78
|
-
end
|
79
|
-
|
80
|
-
def cdn_download!(key)
|
81
|
-
raise "cdn file not found at #{key}" unless cdn_download(key)
|
82
|
-
self
|
83
|
-
end
|
84
|
-
|
85
|
-
def cdn_download(key)
|
86
|
-
download("#{Dronejob::Base.option(:cdn_url)}/#{key}")
|
87
|
-
end
|
88
|
-
|
89
|
-
def download(url)
|
90
|
-
open(full_path, "wb") do |file|
|
91
|
-
file << open(url, { ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE, allow_redirections: :safe }).read
|
92
|
-
end
|
93
|
-
return self
|
94
|
-
rescue StandardError => e
|
95
|
-
return false
|
96
|
-
end
|
97
|
-
|
98
|
-
def extract(target_dir)
|
99
|
-
target_dir.create
|
100
|
-
Zip::File.open(full_path) do |zip_file|
|
101
|
-
zip_file.each do |entry|
|
102
|
-
entry.extract(File.join(target_dir.full_path, entry.name))
|
103
|
-
end
|
104
|
-
end
|
105
|
-
self
|
106
|
-
end
|
107
|
-
|
108
|
-
def acbaker(type, output_dir, delete=true)
|
109
|
-
require "acbaker"
|
110
|
-
output_dir.delete! if delete and output_dir.exists?
|
111
|
-
output_dir.create
|
112
|
-
config = WorkspaceDir.new("app/assets").file("acbaker/#{type}.json").read_json
|
113
|
-
acb = Acbaker::AssetPack.new(type, json: config)
|
114
|
-
acb.process(full_path, output_dir.full_path)
|
115
|
-
self
|
59
|
+
File.open(to_s).read
|
116
60
|
end
|
117
61
|
|
118
62
|
def dir
|
119
63
|
WorkspaceDir.new(@workspace, File.dirname(@path))
|
120
64
|
end
|
121
|
-
|
65
|
+
|
122
66
|
def delete!
|
123
|
-
FileUtils.rm_f(
|
67
|
+
FileUtils.rm_f(to_s)
|
68
|
+
end
|
69
|
+
|
70
|
+
def basename
|
71
|
+
File.basename(path, ".*")
|
72
|
+
end
|
73
|
+
|
74
|
+
def extension
|
75
|
+
File.extname(to_s).gsub(/^\./, "")
|
76
|
+
end
|
77
|
+
|
78
|
+
def rename!(filename)
|
79
|
+
FileUtils.mv(to_s, dir.file(filename).to_s) if exists?
|
80
|
+
@path = dir.file(filename).path
|
124
81
|
end
|
125
82
|
end
|
126
83
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dronejob
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tobias Strebitzer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-04-
|
11
|
+
date: 2016-04-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -150,6 +150,20 @@ dependencies:
|
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '4.2'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: typhoeus
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '1.0'
|
160
|
+
type: :runtime
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '1.0'
|
153
167
|
- !ruby/object:Gem::Dependency
|
154
168
|
name: rspec
|
155
169
|
requirement: !ruby/object:Gem::Requirement
|
@@ -204,14 +218,19 @@ files:
|
|
204
218
|
- lib/dronejob/modules/params.rb
|
205
219
|
- lib/dronejob/modules/phases.rb
|
206
220
|
- lib/dronejob/modules/queue.rb
|
221
|
+
- lib/dronejob/modules/stateful.rb
|
207
222
|
- lib/dronejob/modules/workspace.rb
|
208
|
-
- lib/dronejob/one_off.rb
|
209
223
|
- lib/dronejob/railtie.rb
|
210
224
|
- lib/dronejob/railties/dronejob.rake
|
211
225
|
- lib/dronejob/server/sidekiq.rb
|
212
226
|
- lib/dronejob/version.rb
|
213
227
|
- lib/dronejob/workspace_dir.rb
|
228
|
+
- lib/dronejob/workspace_dir/archive.rb
|
214
229
|
- lib/dronejob/workspace_file.rb
|
230
|
+
- lib/dronejob/workspace_file/archive.rb
|
231
|
+
- lib/dronejob/workspace_file/media.rb
|
232
|
+
- lib/dronejob/workspace_file/net.rb
|
233
|
+
- lib/dronejob/workspace_file/parse.rb
|
215
234
|
homepage: https://github.com/MagLoft/dronejob
|
216
235
|
licenses:
|
217
236
|
- BSD-3-Clause
|
data/lib/dronejob/one_off.rb
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
require "active_job"
|
2
|
-
require 'dronejob/modules/core'
|
3
|
-
require 'dronejob/modules/log'
|
4
|
-
require 'dronejob/modules/options'
|
5
|
-
require 'dronejob/modules/params'
|
6
|
-
require 'dronejob/modules/phases'
|
7
|
-
|
8
|
-
module Dronejob
|
9
|
-
class OneOff
|
10
|
-
DRONEJOB_TYPE = "one_off"
|
11
|
-
include Modules::Core
|
12
|
-
include Modules::Log
|
13
|
-
include Modules::Options
|
14
|
-
include Modules::Params
|
15
|
-
include Modules::Phases
|
16
|
-
|
17
|
-
def perform(params)
|
18
|
-
@params = params
|
19
|
-
validate_parameters!
|
20
|
-
|
21
|
-
# Run through phases
|
22
|
-
each_phase do |phase, config|
|
23
|
-
begin
|
24
|
-
phase_result = public_send(phase)
|
25
|
-
rescue Exception => e
|
26
|
-
error(e.message)
|
27
|
-
error(e.backtrace.join("\n"))
|
28
|
-
return false
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def each_phase(&block)
|
34
|
-
self.class.phases.each do |phase, config|
|
35
|
-
fail "Phase not found: '#{phase}'" unless self.respond_to?(phase)
|
36
|
-
@phase = phase
|
37
|
-
before_phase(phase, config) if self.respond_to?(:before_phase)
|
38
|
-
|
39
|
-
logger.tagged(phase) do
|
40
|
-
if completed_phase?(phase) and !config[:always_run]
|
41
|
-
info("already completed")
|
42
|
-
elsif skip_phase?(phase)
|
43
|
-
info("skipping...")
|
44
|
-
else
|
45
|
-
# Require libraries
|
46
|
-
if !config[:require].nil?
|
47
|
-
config[:require].each do |library|
|
48
|
-
require library
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# Include helpers
|
53
|
-
if !config[:helpers].nil?
|
54
|
-
config[:helpers].each do |helper|
|
55
|
-
helper_path = "helpers/#{helper}"
|
56
|
-
require "./app/#{helper_path}"
|
57
|
-
self.class.include helper_path.camelcase.constantize
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
block.call(phase, config)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
after_phase(phase, config) if self.respond_to?(:after_phase)
|
66
|
-
end
|
67
|
-
|
68
|
-
info("JOB COMPLETED")
|
69
|
-
end
|
70
|
-
|
71
|
-
def completed_phase?(phase)
|
72
|
-
false
|
73
|
-
end
|
74
|
-
|
75
|
-
ActiveSupport.run_load_hooks(:dronejob, self)
|
76
|
-
end
|
77
|
-
end
|