constable 0.1.0 → 0.2.0
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.
- data/README.md +39 -8
- data/bin/constable-convert +47 -0
- data/bin/constable-identify +18 -17
- data/bin/constabled +94 -25
- data/lib/constable/version.rb +1 -1
- metadata +5 -4
data/README.md
CHANGED
@@ -8,6 +8,33 @@ anything quite as powerful will be generated using the service, but if you do
|
|
8
8
|
make something nice please let me know!
|
9
9
|
|
10
10
|
|
11
|
+
Up and running fast
|
12
|
+
-------------------
|
13
|
+
|
14
|
+
I've provided a Vagrant setup that will get you up and running fast. Install
|
15
|
+
the necessary gems using bundler:
|
16
|
+
|
17
|
+
cd /path/to/checkout/of/constable
|
18
|
+
bundle
|
19
|
+
|
20
|
+
Ask Vagrant to bring up the server components for you:
|
21
|
+
|
22
|
+
cd /path/to/checkout/of/constable
|
23
|
+
bundle exec vagrant up
|
24
|
+
|
25
|
+
Ask Constable to do some work:
|
26
|
+
|
27
|
+
cd /path/to/checkout/of/constable
|
28
|
+
bundle exec ./bin/constable-identify -- /path/to/input.png -verbose
|
29
|
+
|
30
|
+
That's it, you just used ImageMagick as a service.
|
31
|
+
|
32
|
+
Of course, if you want to use it as a real service on your network you'll
|
33
|
+
probably want to set it up a little differently. See the following sections on
|
34
|
+
Installing and Usage for information on how to setup your own ImageMagick
|
35
|
+
service.
|
36
|
+
|
37
|
+
|
11
38
|
Installing
|
12
39
|
----------
|
13
40
|
|
@@ -31,9 +58,9 @@ and I'll pull your changes.
|
|
31
58
|
|
32
59
|
Run the server, somewhere that has ImageMagick installed:
|
33
60
|
|
34
|
-
constabled --broker=stomp://mq.yourdomain.com:61613
|
61
|
+
$ constabled --broker=stomp://mq.yourdomain.com:61613
|
35
62
|
|
36
|
-
Use the services on the command line. You don't need
|
63
|
+
Use the services on the command line. You don't need to have ImageMagick
|
37
64
|
installed on your client machines, just constable.
|
38
65
|
|
39
66
|
Command names are based on ImageMagick command names, prefixed with
|
@@ -41,16 +68,20 @@ Command names are based on ImageMagick command names, prefixed with
|
|
41
68
|
and will give you a decent explanation of what they do and their options if
|
42
69
|
you ask for it.
|
43
70
|
|
44
|
-
The commands are designed to take their input
|
45
|
-
results on standard output. It's up to you what you do with the
|
46
|
-
|
47
|
-
|
71
|
+
The commands are designed to take their input just like ImageMagick and return
|
72
|
+
results on standard output. It's up to you what you do with the output;
|
73
|
+
write it to a file, pipe it to another process, that's not handled by Constable.
|
74
|
+
A caveat of this is that you must construct your Constable invocations such that
|
75
|
+
ImageMagick would write to standard output rather than a file.
|
48
76
|
|
49
77
|
A brief example of what interacting with Constable looks like, here
|
50
78
|
identifying some image file I had lying around on disk:
|
51
79
|
|
52
|
-
$
|
53
|
-
|
80
|
+
$ constable-identify --broker=stomp://mq.yourdomain.com:61613 -- input_file
|
81
|
+
input_file JPEG 640x480 DirectClass 87kb 0.050u 0:01
|
82
|
+
|
83
|
+
$ constable-convert --broker=stomp://mq.yourdomain.com:61613 -- \
|
84
|
+
-resize 50% input.png jpg:- > output.jpg
|
54
85
|
|
55
86
|
I explicitly state the broker in the above commands but if you leave out that
|
56
87
|
option it'll default to stomp://localhost:61613 ie it expects a broker running
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
require 'stomp'
|
5
|
+
require 'json'
|
6
|
+
require "getoptlong"
|
7
|
+
|
8
|
+
options = {}
|
9
|
+
argv = GetoptLong.new(
|
10
|
+
[ "--broker", "-b", GetoptLong::OPTIONAL_ARGUMENT ]
|
11
|
+
)
|
12
|
+
argv.each do |option, value|
|
13
|
+
options['broker'] = value if option == '--broker'
|
14
|
+
end
|
15
|
+
options['broker'] ||= 'stomp://127.0.0.1:61613'
|
16
|
+
|
17
|
+
parameters = ARGV.join ' '
|
18
|
+
command = {
|
19
|
+
command: File.basename($0).gsub(/^constable-/, ''),
|
20
|
+
parameters: parameters,
|
21
|
+
files: {}
|
22
|
+
}
|
23
|
+
ARGV.each do |file_name|
|
24
|
+
if File.exists? file_name
|
25
|
+
file = File.read file_name
|
26
|
+
data = Base64.encode64 file
|
27
|
+
command[:files][file_name] = data
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
command_json = JSON.generate command
|
32
|
+
|
33
|
+
results = '/queue/constable.results-' + Process.pid.to_s + '-' + Time.now.to_i.to_s
|
34
|
+
client = Stomp::Client.new options['broker']
|
35
|
+
client.publish '/queue/constable', command_json, 'reply-to' => results
|
36
|
+
|
37
|
+
client.subscribe results, 'auto-delete' => true do |message|
|
38
|
+
results = JSON.parse message.body
|
39
|
+
if results['exit_code'] == 0
|
40
|
+
print results['stdout']
|
41
|
+
else
|
42
|
+
print results['stderr']
|
43
|
+
end
|
44
|
+
client.close
|
45
|
+
end
|
46
|
+
|
47
|
+
client.join
|
data/bin/constable-identify
CHANGED
@@ -1,14 +1,6 @@
|
|
1
1
|
#! /usr/bin/env ruby
|
2
2
|
|
3
|
-
image = STDIN.read
|
4
|
-
if image.to_s == ''
|
5
|
-
puts "Give me some input!"
|
6
|
-
exit 1
|
7
|
-
end
|
8
|
-
|
9
3
|
require 'base64'
|
10
|
-
encoded_input = Base64.encode64 image
|
11
|
-
|
12
4
|
require 'stomp'
|
13
5
|
require 'json'
|
14
6
|
require "getoptlong"
|
@@ -22,8 +14,26 @@ argv.each do |option, value|
|
|
22
14
|
end
|
23
15
|
options['broker'] ||= 'stomp://127.0.0.1:61613'
|
24
16
|
|
17
|
+
parameters = ARGV.join ' '
|
18
|
+
command = {
|
19
|
+
command: File.basename($0).gsub(/^constable-/, ''),
|
20
|
+
parameters: parameters,
|
21
|
+
files: {}
|
22
|
+
}
|
23
|
+
ARGV.each do |file_name|
|
24
|
+
if File.exists? file_name
|
25
|
+
file = File.read file_name
|
26
|
+
data = Base64.encode64 file
|
27
|
+
command[:files][file_name] = data
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
command_json = JSON.generate command
|
32
|
+
|
25
33
|
results = '/queue/constable.results-' + Process.pid.to_s + '-' + Time.now.to_i.to_s
|
26
34
|
client = Stomp::Client.new options['broker']
|
35
|
+
client.publish '/queue/constable', command_json, 'reply-to' => results
|
36
|
+
|
27
37
|
client.subscribe results, 'auto-delete' => true do |message|
|
28
38
|
results = JSON.parse message.body
|
29
39
|
if results['exit_code'] == 0
|
@@ -34,13 +44,4 @@ client.subscribe results, 'auto-delete' => true do |message|
|
|
34
44
|
client.close
|
35
45
|
end
|
36
46
|
|
37
|
-
parameters = ARGV.join ' '
|
38
|
-
command = {
|
39
|
-
command: 'identify',
|
40
|
-
input: encoded_input,
|
41
|
-
parameters: parameters
|
42
|
-
}
|
43
|
-
command_json = JSON.generate command
|
44
|
-
|
45
|
-
client.publish '/queue/constable', command_json, 'reply-to' => results
|
46
47
|
client.join
|
data/bin/constabled
CHANGED
@@ -10,38 +10,98 @@ require 'getoptlong'
|
|
10
10
|
|
11
11
|
class Job
|
12
12
|
module WorkingEnvironment
|
13
|
-
def with_temp_file
|
14
|
-
temp_file = Tempfile.new serial
|
15
|
-
yield temp_file
|
16
|
-
ensure
|
17
|
-
temp_file.close!
|
18
|
-
end
|
19
|
-
|
20
13
|
def serial
|
21
14
|
@job_id ||= [
|
22
15
|
File.basename($0), Time.now.to_i, rand(1_000_000)
|
23
16
|
].join '-'
|
24
17
|
end
|
25
18
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
19
|
+
def working_directory
|
20
|
+
@working_directory ||= %x[mktemp -d -t #{serial}-XXXXXX].strip
|
21
|
+
end
|
22
|
+
|
23
|
+
def clean_up
|
24
|
+
%x[ test -d "#{@working_directory}" && rm -rf "#{@working_directory}"]
|
25
|
+
end
|
26
|
+
|
27
|
+
def write_files
|
28
|
+
files.each_pair do |file_name, content|
|
29
|
+
puts "Decoding #{file_name}"
|
30
|
+
decoded_content = Base64.decode64 content
|
31
|
+
puts "Writing #{file_name} content"
|
32
|
+
file = write_file decoded_content, file_name.split(/\./)[-1]
|
33
|
+
puts "Wrote #{file_name} to #{file.path}"
|
34
|
+
rewrite_file_parameter file_name, file.path
|
32
35
|
end
|
33
36
|
end
|
34
37
|
|
35
|
-
def
|
38
|
+
def write_file content, ext = nil
|
39
|
+
hash = Digest::SHA1.hexdigest content
|
40
|
+
ext = ".#{ext}" if ext && ext[0] != '.'
|
41
|
+
file = File.open File.join(working_directory, "#{hash}#{ext}"), 'w+'
|
42
|
+
file.print content
|
43
|
+
file.close
|
44
|
+
file
|
45
|
+
end
|
46
|
+
|
47
|
+
# FIXME: We can still end up with parameters we don't know about being sent
|
48
|
+
# here, including shell escaped... insane.
|
49
|
+
#
|
50
|
+
# Figure out some way to generate a whitelist of ImageMagick commands and
|
51
|
+
# parameters.
|
52
|
+
|
53
|
+
def rewrite_file_parameter file_name, actual_file
|
54
|
+
file_map[actual_file] = file_name
|
55
|
+
puts "Rewriting parameter #{file_name} to #{actual_file}"
|
56
|
+
parameters.gsub! file_name, actual_file
|
57
|
+
end
|
58
|
+
|
59
|
+
def file_map
|
60
|
+
@file_map ||= {}
|
61
|
+
end
|
62
|
+
|
63
|
+
def unwrap_file_parameters result
|
64
|
+
file_map.each_pair do |local_file, remote_file|
|
65
|
+
puts "Rewriting parameter #{local_file} to #{remote_file}"
|
66
|
+
result.gsub! local_file, remote_file
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def files
|
71
|
+
options['files']
|
72
|
+
end
|
73
|
+
|
74
|
+
def parameters
|
75
|
+
options['parameters']
|
76
|
+
end
|
77
|
+
|
78
|
+
def hostname
|
79
|
+
%x[hostname].strip
|
80
|
+
end
|
81
|
+
|
82
|
+
def run_command command
|
83
|
+
write_files
|
84
|
+
command_line = [ command, parameters ].join ' '
|
36
85
|
puts "Running #{command_line}"
|
37
|
-
stdin, stdout, stderr
|
86
|
+
stdin, stdout, stderr = Open3.popen3 command_line
|
87
|
+
output = stdout.readlines.join
|
88
|
+
errors = stderr.readlines.join
|
89
|
+
unwrap_file_parameters command_line
|
90
|
+
unwrap_file_parameters output
|
38
91
|
{
|
39
|
-
stdout
|
40
|
-
stderr
|
41
|
-
|
42
|
-
|
43
|
-
|
92
|
+
:stdout => output,
|
93
|
+
:stderr => errors,
|
94
|
+
:command_line => command_line,
|
95
|
+
:exit_code => $?.exitstatus,
|
96
|
+
:pid => $?.pid,
|
97
|
+
:working_directory => working_directory,
|
98
|
+
:processor => {
|
99
|
+
:hostname => hostname,
|
100
|
+
:pid => Process.pid
|
101
|
+
}
|
44
102
|
}
|
103
|
+
ensure
|
104
|
+
clean_up
|
45
105
|
end
|
46
106
|
end
|
47
107
|
|
@@ -56,13 +116,22 @@ class Job
|
|
56
116
|
end
|
57
117
|
|
58
118
|
def execute
|
59
|
-
|
60
|
-
run_command "identify #{parameters} #{file.path}"
|
61
|
-
end
|
119
|
+
run_command :identify
|
62
120
|
end
|
121
|
+
end
|
63
122
|
|
64
|
-
|
65
|
-
|
123
|
+
class ConvertCommand
|
124
|
+
include WorkingEnvironment
|
125
|
+
|
126
|
+
attr_accessor :options
|
127
|
+
private :options, :options=
|
128
|
+
|
129
|
+
def initialize options
|
130
|
+
self.options = options
|
131
|
+
end
|
132
|
+
|
133
|
+
def execute
|
134
|
+
run_command :convert
|
66
135
|
end
|
67
136
|
end
|
68
137
|
|
data/lib/constable/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: constable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-10-03 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: stomp
|
16
|
-
requirement: &
|
16
|
+
requirement: &70206086170300 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70206086170300
|
25
25
|
description: Installing ImageMagick and RMagick everywhere sucks, right? So install
|
26
26
|
it in one place and have everything else use that one install.
|
27
27
|
email:
|
@@ -34,6 +34,7 @@ extra_rdoc_files: []
|
|
34
34
|
files:
|
35
35
|
- lib/constable/version.rb
|
36
36
|
- lib/constable.rb
|
37
|
+
- bin/constable-convert
|
37
38
|
- bin/constable-identify
|
38
39
|
- bin/constabled
|
39
40
|
- README.md
|