rakit 0.1.7 → 0.1.8
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/lib/rakit/cli/word_cloud.rb +225 -0
- data/lib/rakit/word_cloud.rb +247 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 618281ffaa52461777b6cf921c5290e89dc503ef845adc9410d4934d917ed285
|
|
4
|
+
data.tar.gz: c3b90837302fb00dac1987e6c181307480ab7133fe113dc65805b307e0c2ed3a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9c9b06b9a2fce44ff8cb4b99993c2a6caff13a9b5155cb2202b23000faccdc82853201134bff2cef57bd17400e038d86d6ef3437239c26409587ed78ef3b3c30
|
|
7
|
+
data.tar.gz: 4b3624c2093bde3d3f0a42959a511793e231dc2fba0a6e2cf7baac4613812355764a11a195cd76ec8abfa7c082813e38243e7276e94de19505fd33499827d0ca
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "google/protobuf"
|
|
5
|
+
require "rakit/word_cloud"
|
|
6
|
+
|
|
7
|
+
module Rakit
|
|
8
|
+
module CLI
|
|
9
|
+
module WordCloud
|
|
10
|
+
class << self
|
|
11
|
+
# @param argv [Array<String>] arguments after "word-cloud"
|
|
12
|
+
# @return [Integer] exit code
|
|
13
|
+
def run(argv)
|
|
14
|
+
return usage_stderr("Expected command: status | install | generate") if argv.empty?
|
|
15
|
+
|
|
16
|
+
cmd = argv.shift
|
|
17
|
+
case cmd
|
|
18
|
+
when "status" then run_status(argv)
|
|
19
|
+
when "install" then run_install(argv)
|
|
20
|
+
when "generate" then run_generate(argv)
|
|
21
|
+
else
|
|
22
|
+
$stderr.puts "Unknown command: #{cmd}"
|
|
23
|
+
1
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def parse_format(argv)
|
|
30
|
+
format = "console"
|
|
31
|
+
args = argv.dup
|
|
32
|
+
i = args.index("--format")
|
|
33
|
+
if i && args[i + 1]
|
|
34
|
+
format = args[i + 1]
|
|
35
|
+
args.delete_at(i + 1)
|
|
36
|
+
args.delete_at(i)
|
|
37
|
+
end
|
|
38
|
+
[format, args]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def run_status(argv)
|
|
42
|
+
format, _ = parse_format(argv)
|
|
43
|
+
st = Rakit::WordCloud.status({})
|
|
44
|
+
render_tool_status(st, format)
|
|
45
|
+
0
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def run_install(argv)
|
|
49
|
+
format, _ = parse_format(argv)
|
|
50
|
+
result = Rakit::WordCloud.install({})
|
|
51
|
+
render_install_result(result, format)
|
|
52
|
+
result.success ? 0 : 1
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def run_generate(argv)
|
|
56
|
+
format, rest = parse_format(argv)
|
|
57
|
+
opts = parse_generate_opts(rest)
|
|
58
|
+
return 1 if opts[:error]
|
|
59
|
+
|
|
60
|
+
request = build_generate_request(opts)
|
|
61
|
+
return 1 unless request
|
|
62
|
+
|
|
63
|
+
stdin_content = opts[:stdin] ? $stdin.read : nil
|
|
64
|
+
result = Rakit::WordCloud.generate(request, stdin_content: stdin_content)
|
|
65
|
+
|
|
66
|
+
if opts[:publish_site_name] && result.success && defined?(Rakit::StaticWebServer)
|
|
67
|
+
out_dir = ::File.dirname(result.output_image.to_s)
|
|
68
|
+
begin
|
|
69
|
+
Rakit::StaticWebServer.publish(opts[:publish_site_name], out_dir)
|
|
70
|
+
rescue => e
|
|
71
|
+
$stderr.puts "Publish failed: #{e.message}"
|
|
72
|
+
return 1
|
|
73
|
+
end
|
|
74
|
+
elsif opts[:publish_site_name] && result.success && !defined?(Rakit::StaticWebServer)
|
|
75
|
+
$stderr.puts "Publish requested but StaticWebServer not available. Require the static web server feature."
|
|
76
|
+
return 1
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
render_generate_result(result, format)
|
|
80
|
+
result.success ? 0 : 1
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def parse_generate_opts(argv)
|
|
84
|
+
opts = {
|
|
85
|
+
format: "console",
|
|
86
|
+
text_file: nil,
|
|
87
|
+
inline_text: nil,
|
|
88
|
+
stdin: false,
|
|
89
|
+
out: nil,
|
|
90
|
+
width: nil,
|
|
91
|
+
height: nil,
|
|
92
|
+
seed: nil,
|
|
93
|
+
mask: nil,
|
|
94
|
+
font: nil,
|
|
95
|
+
exclude_words: nil,
|
|
96
|
+
max_words: nil,
|
|
97
|
+
auto_install: false,
|
|
98
|
+
publish_site_name: nil,
|
|
99
|
+
working_directory: nil
|
|
100
|
+
}
|
|
101
|
+
args = argv.dup
|
|
102
|
+
while (arg = args.shift)
|
|
103
|
+
case arg
|
|
104
|
+
when "--text" then opts[:text_file] = args.shift
|
|
105
|
+
when "--inline" then opts[:inline_text] = args.shift
|
|
106
|
+
when "--stdin" then opts[:stdin] = true
|
|
107
|
+
when "--out" then opts[:out] = args.shift
|
|
108
|
+
when "--width" then opts[:width] = (args.shift || "0").to_i
|
|
109
|
+
when "--height" then opts[:height] = (args.shift || "0").to_i
|
|
110
|
+
when "--seed" then opts[:seed] = (args.shift || "-1").to_i
|
|
111
|
+
when "--mask" then opts[:mask] = args.shift
|
|
112
|
+
when "--font" then opts[:font] = args.shift
|
|
113
|
+
when "--exclude-words" then opts[:exclude_words] = args.shift
|
|
114
|
+
when "--max-words" then opts[:max_words] = (args.shift || "0").to_i
|
|
115
|
+
when "--auto-install" then opts[:auto_install] = true
|
|
116
|
+
when "--publish" then opts[:publish_site_name] = args.shift
|
|
117
|
+
when "--working-directory" then opts[:working_directory] = args.shift
|
|
118
|
+
when /^--/
|
|
119
|
+
$stderr.puts "Unknown option: #{arg}"
|
|
120
|
+
opts[:error] = true
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
opts
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def build_generate_request(opts)
|
|
127
|
+
unless opts[:out] && opts[:out].to_s.strip != ""
|
|
128
|
+
$stderr.puts "generate requires --out PATH"
|
|
129
|
+
return nil
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
has_file = opts[:text_file] && opts[:text_file].to_s.strip != ""
|
|
133
|
+
has_inline = opts[:inline_text] && opts[:inline_text].to_s.strip != ""
|
|
134
|
+
has_stdin = opts[:stdin]
|
|
135
|
+
count = [has_file, has_inline, has_stdin].count(true)
|
|
136
|
+
unless count == 1
|
|
137
|
+
$stderr.puts "Provide exactly one of: --text FILE, --inline \"string\", or --stdin"
|
|
138
|
+
return nil
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
gen = Rakit::Generated
|
|
142
|
+
config = gen::WordCloudConfig.new(
|
|
143
|
+
wcloud_path: "",
|
|
144
|
+
auto_install: opts[:auto_install],
|
|
145
|
+
working_directory: (opts[:working_directory] || "").to_s
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
text = if opts[:text_file] && opts[:text_file].to_s.strip != ""
|
|
149
|
+
gen::TextSource.new(text_file: opts[:text_file].to_s)
|
|
150
|
+
elsif opts[:inline_text] && opts[:inline_text].to_s.strip != ""
|
|
151
|
+
gen::TextSource.new(inline_text: opts[:inline_text].to_s)
|
|
152
|
+
else
|
|
153
|
+
gen::TextSource.new(stdin: true)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
req = gen::GenerateRequest.new(
|
|
157
|
+
config: config,
|
|
158
|
+
text: text,
|
|
159
|
+
output_image: opts[:out].to_s,
|
|
160
|
+
width: opts[:width] || 0,
|
|
161
|
+
height: opts[:height] || 0,
|
|
162
|
+
rng_seed: opts[:seed] || -1,
|
|
163
|
+
mask_image: (opts[:mask] || "").to_s,
|
|
164
|
+
font_file: (opts[:font] || "").to_s,
|
|
165
|
+
exclude_words_file: (opts[:exclude_words] || "").to_s,
|
|
166
|
+
max_words: opts[:max_words] || 0
|
|
167
|
+
)
|
|
168
|
+
req
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def render_tool_status(st, format)
|
|
172
|
+
case format
|
|
173
|
+
when "json"
|
|
174
|
+
puts ({ wcloud_found: st.wcloud_found, wcloud_path: st.wcloud_path, cargo_found: st.cargo_found, cargo_path: st.cargo_path }.to_json)
|
|
175
|
+
when "proto-json"
|
|
176
|
+
puts Google::Protobuf.encode_json(st)
|
|
177
|
+
else
|
|
178
|
+
puts "wcloud: #{st.wcloud_found ? st.wcloud_path : 'not found'}"
|
|
179
|
+
puts "cargo: #{st.cargo_found ? st.cargo_path : 'not found'}"
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def render_install_result(result, format)
|
|
184
|
+
case format
|
|
185
|
+
when "json"
|
|
186
|
+
puts ({ success: result.success, message: result.message, stderr: result.stderr }.to_json)
|
|
187
|
+
when "proto-json"
|
|
188
|
+
puts Google::Protobuf.encode_json(result)
|
|
189
|
+
else
|
|
190
|
+
unless result.success
|
|
191
|
+
$stderr.puts result.message
|
|
192
|
+
$stderr.puts result.stderr if result.stderr.to_s.strip != ""
|
|
193
|
+
else
|
|
194
|
+
puts result.message
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def render_generate_result(result, format)
|
|
200
|
+
unless result.success
|
|
201
|
+
$stderr.puts result.message
|
|
202
|
+
$stderr.puts result.stderr if result.stderr.to_s.strip != "" && result.stderr != result.message
|
|
203
|
+
end
|
|
204
|
+
case format
|
|
205
|
+
when "json"
|
|
206
|
+
h = { success: result.success, message: result.message, output_image: result.output_image, exit_code: result.exit_code }
|
|
207
|
+
puts h.to_json
|
|
208
|
+
when "proto-json"
|
|
209
|
+
puts Google::Protobuf.encode_json(result)
|
|
210
|
+
else
|
|
211
|
+
puts result.message if result.success
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def usage_stderr(msg)
|
|
216
|
+
$stderr.puts msg
|
|
217
|
+
$stderr.puts " word-cloud status [--format console|json|proto-json]"
|
|
218
|
+
$stderr.puts " word-cloud install [--format ...]"
|
|
219
|
+
$stderr.puts " word-cloud generate (--text FILE|--inline \"string\"|--stdin) --out PATH [options]"
|
|
220
|
+
1
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "generated/word_cloud_pb"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
require "open3"
|
|
6
|
+
|
|
7
|
+
module Rakit
|
|
8
|
+
module WordCloud
|
|
9
|
+
class << self
|
|
10
|
+
attr_accessor :wcloud_path, :auto_install, :working_directory
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
self.auto_install = false
|
|
14
|
+
|
|
15
|
+
# Validate path has no traversal. If relative, must be under base_dir; absolute paths allowed.
|
|
16
|
+
def self.path_safe?(path, base_dir)
|
|
17
|
+
return false if path.nil? || path.to_s.strip.empty?
|
|
18
|
+
p = path.to_s.strip
|
|
19
|
+
return false if p.include?("..")
|
|
20
|
+
base = ::File.expand_path(base_dir.to_s)
|
|
21
|
+
expanded = ::File.expand_path(p, base)
|
|
22
|
+
# Absolute path: allow (no traversal)
|
|
23
|
+
return true if p.start_with?("/") || (p.size >= 2 && p[1] == ":")
|
|
24
|
+
expanded == base || expanded.start_with?(base + ::File::SEPARATOR)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Validate text file path: exists, readable file, no traversal. base_dir = working_directory or Dir.pwd.
|
|
28
|
+
def self.validate_text_file_path(path, base_dir)
|
|
29
|
+
base = ::File.expand_path(base_dir.to_s)
|
|
30
|
+
expanded = ::File.expand_path(path.to_s, base)
|
|
31
|
+
return [false, "Path contains traversal (..) or is outside working directory"] unless path_safe?(path, base_dir)
|
|
32
|
+
return [false, "File does not exist: #{path}"] unless ::File.exist?(expanded)
|
|
33
|
+
return [false, "Not a file: #{path}"] unless ::File.file?(expanded)
|
|
34
|
+
return [false, "File not readable: #{path}"] unless ::File.readable?(expanded)
|
|
35
|
+
[true, expanded]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Validate output image path: parent creatable/writable, no traversal.
|
|
39
|
+
def self.validate_output_path(path, base_dir)
|
|
40
|
+
base = ::File.expand_path(base_dir.to_s)
|
|
41
|
+
expanded = ::File.expand_path(path.to_s, base)
|
|
42
|
+
return [false, "Path contains traversal (..) or is outside working directory"] unless path_safe?(path, base_dir)
|
|
43
|
+
parent = ::File.dirname(expanded)
|
|
44
|
+
begin
|
|
45
|
+
FileUtils.mkdir_p(parent) unless ::File.directory?(parent)
|
|
46
|
+
rescue SystemCallError => e
|
|
47
|
+
return [false, "Cannot create output directory: #{e.message}"]
|
|
48
|
+
end
|
|
49
|
+
return [false, "Output path not writable: #{path}"] unless ::File.writable?(parent)
|
|
50
|
+
[true, expanded]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Validate optional file path (mask, font, exclude-words): if present, must exist and be readable.
|
|
54
|
+
def self.validate_optional_file_path(path, base_dir, label)
|
|
55
|
+
return [true, nil] if path.nil? || path.to_s.strip.empty?
|
|
56
|
+
base = ::File.expand_path(base_dir.to_s)
|
|
57
|
+
expanded = ::File.expand_path(path.to_s, base)
|
|
58
|
+
return [false, "#{label}: path contains traversal or is outside working directory"] unless path_safe?(path, base_dir)
|
|
59
|
+
return [false, "#{label} file does not exist: #{path}"] unless ::File.exist?(expanded)
|
|
60
|
+
return [false, "#{label} not a file: #{path}"] unless ::File.file?(expanded)
|
|
61
|
+
return [false, "#{label} not readable: #{path}"] unless ::File.readable?(expanded)
|
|
62
|
+
[true, expanded]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Resolve wcloud: config path, then ENV RAKIT_WCLOUD_BINARY, then which wcloud.
|
|
66
|
+
def self.resolve_wcloud(config = {})
|
|
67
|
+
path = config[:wcloud_path] || config["wcloud_path"] || self.wcloud_path
|
|
68
|
+
return path if path && path.to_s.strip != "" && ::File.executable?(::File.expand_path(path))
|
|
69
|
+
env_path = ENV["RAKIT_WCLOUD_BINARY"]
|
|
70
|
+
return env_path if env_path && env_path.to_s.strip != "" && ::File.executable?(::File.expand_path(env_path))
|
|
71
|
+
which("wcloud")
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Resolve cargo: which cargo.
|
|
75
|
+
def self.resolve_cargo(_config = {})
|
|
76
|
+
which("cargo")
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Status: resolve wcloud and cargo; no side effects. Returns ToolStatus.
|
|
80
|
+
def self.status(config = {})
|
|
81
|
+
cfg = config.is_a?(Hash) ? config : {}
|
|
82
|
+
wcloud_path = cfg[:wcloud_path] || cfg["wcloud_path"] || self.wcloud_path
|
|
83
|
+
wcloud_bin = resolve_wcloud(cfg)
|
|
84
|
+
cargo_bin = resolve_cargo(cfg)
|
|
85
|
+
Rakit::Generated::ToolStatus.new(
|
|
86
|
+
wcloud_found: !wcloud_bin.nil?,
|
|
87
|
+
wcloud_path: wcloud_bin.to_s,
|
|
88
|
+
cargo_found: !cargo_bin.nil?,
|
|
89
|
+
cargo_path: cargo_bin.to_s
|
|
90
|
+
)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Install: run cargo install wcloud. Returns GenerateResult with success, message, stderr.
|
|
94
|
+
def self.install(config = {})
|
|
95
|
+
cfg = config.is_a?(Hash) ? config : {}
|
|
96
|
+
cargo_bin = resolve_cargo(cfg)
|
|
97
|
+
unless cargo_bin
|
|
98
|
+
return fail_result("", "cargo not found. Install Rust from https://rustup.rs/ then run: cargo install wcloud", -1)
|
|
99
|
+
end
|
|
100
|
+
_stdout, stderr, status = Open3.capture3(cargo_bin, "install", "wcloud")
|
|
101
|
+
Rakit::Generated::GenerateResult.new(
|
|
102
|
+
success: status.success?,
|
|
103
|
+
message: status.success? ? "wcloud installed or already present" : stderr.to_s.strip,
|
|
104
|
+
output_image: "",
|
|
105
|
+
exit_code: status.exitstatus,
|
|
106
|
+
stdout: "",
|
|
107
|
+
stderr: stderr.to_s
|
|
108
|
+
)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def self.which(cmd)
|
|
112
|
+
exe = nil
|
|
113
|
+
ENV["PATH"].to_s.split(::File::PATH_SEPARATOR).each do |dir|
|
|
114
|
+
full = ::File.join(dir.strip, cmd)
|
|
115
|
+
if ::File.executable?(full)
|
|
116
|
+
exe = full
|
|
117
|
+
break
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
exe
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Generate word cloud. request is GenerateRequest. Optional stdin_content when text source is stdin.
|
|
124
|
+
# Returns GenerateResult. Does not leave partial output on validation or tool failure.
|
|
125
|
+
def self.generate(request, stdin_content: nil)
|
|
126
|
+
cfg = request.config || Rakit::Generated::WordCloudConfig.new
|
|
127
|
+
base_dir = (cfg.working_directory.to_s.strip != "") ? cfg.working_directory : (self.working_directory || Dir.pwd)
|
|
128
|
+
|
|
129
|
+
# Resolve text content and validate non-empty
|
|
130
|
+
content, err = resolve_text_content(request.text, base_dir, stdin_content)
|
|
131
|
+
unless content
|
|
132
|
+
return fail_result(request.output_image.to_s, err, -1)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Validate output path (creates parent if missing)
|
|
136
|
+
ok, out_path = validate_output_path(request.output_image.to_s, base_dir)
|
|
137
|
+
unless ok
|
|
138
|
+
return fail_result(request.output_image.to_s, out_path, -1)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Optional file paths (mask, font, exclude-words)
|
|
142
|
+
mask_path = request.mask_image.to_s.strip
|
|
143
|
+
if mask_path != ""
|
|
144
|
+
ok, err = validate_optional_file_path(mask_path, base_dir, "Mask image")
|
|
145
|
+
return fail_result(out_path, err, -1) unless ok
|
|
146
|
+
end
|
|
147
|
+
font_path = request.font_file.to_s.strip
|
|
148
|
+
if font_path != ""
|
|
149
|
+
ok, err = validate_optional_file_path(font_path, base_dir, "Font file")
|
|
150
|
+
return fail_result(out_path, err, -1) unless ok
|
|
151
|
+
end
|
|
152
|
+
exclude_path = request.exclude_words_file.to_s.strip
|
|
153
|
+
if exclude_path != ""
|
|
154
|
+
ok, err = validate_optional_file_path(exclude_path, base_dir, "Exclude-words file")
|
|
155
|
+
return fail_result(out_path, err, -1) unless ok
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
config_hash = { wcloud_path: cfg.wcloud_path.to_s, auto_install: cfg.auto_install }
|
|
159
|
+
wcloud_bin = resolve_wcloud(config_hash)
|
|
160
|
+
if wcloud_bin.nil? && cfg.auto_install
|
|
161
|
+
install_result = install(config_hash)
|
|
162
|
+
unless install_result.success
|
|
163
|
+
return fail_result(out_path, "wcloud not found and auto-install failed: #{install_result.message}", -1)
|
|
164
|
+
end
|
|
165
|
+
wcloud_bin = resolve_wcloud(config_hash)
|
|
166
|
+
end
|
|
167
|
+
unless wcloud_bin
|
|
168
|
+
return fail_result(out_path, "wcloud not found. Install with: cargo install wcloud", -1)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
argv = build_wcloud_argv(request, out_path, mask_path, font_path, exclude_path)
|
|
172
|
+
stdout, stderr, exit_code = run_wcloud(wcloud_bin, argv, stdin: content)
|
|
173
|
+
|
|
174
|
+
result = Rakit::Generated::GenerateResult.new(
|
|
175
|
+
success: exit_code == 0,
|
|
176
|
+
message: exit_code == 0 ? "OK" : stderr.to_s.strip,
|
|
177
|
+
output_image: out_path,
|
|
178
|
+
exit_code: exit_code,
|
|
179
|
+
stdout: stdout.to_s,
|
|
180
|
+
stderr: stderr.to_s,
|
|
181
|
+
wcloud_resolved_path: wcloud_bin
|
|
182
|
+
)
|
|
183
|
+
unless result.success
|
|
184
|
+
::File.unlink(out_path) if ::File.exist?(out_path)
|
|
185
|
+
end
|
|
186
|
+
result
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def self.fail_result(output_image, message, exit_code)
|
|
190
|
+
Rakit::Generated::GenerateResult.new(
|
|
191
|
+
success: false,
|
|
192
|
+
message: message.to_s,
|
|
193
|
+
output_image: output_image.to_s,
|
|
194
|
+
exit_code: exit_code,
|
|
195
|
+
stdout: "",
|
|
196
|
+
stderr: message.to_s
|
|
197
|
+
)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def self.resolve_text_content(text_source, base_dir, stdin_content)
|
|
201
|
+
return [nil, "Text source is empty; provide non-empty text."] if text_source.nil?
|
|
202
|
+
|
|
203
|
+
case text_source.source
|
|
204
|
+
when :text_file
|
|
205
|
+
path = text_source.text_file.to_s.strip
|
|
206
|
+
return [nil, "Text file path is empty."] if path.empty?
|
|
207
|
+
ok, expanded = validate_text_file_path(path, base_dir)
|
|
208
|
+
return [nil, expanded] unless ok
|
|
209
|
+
content = ::File.read(expanded)
|
|
210
|
+
return [nil, "Text source is empty; provide non-empty text."] if content.to_s.strip.empty?
|
|
211
|
+
return [content, nil]
|
|
212
|
+
when :inline_text
|
|
213
|
+
content = text_source.inline_text.to_s
|
|
214
|
+
return [nil, "Text source is empty; provide non-empty text."] if content.strip.empty?
|
|
215
|
+
return [content, nil]
|
|
216
|
+
when :stdin
|
|
217
|
+
content = stdin_content.to_s
|
|
218
|
+
return [nil, "Text source is empty; provide non-empty text."] if content.strip.empty?
|
|
219
|
+
return [content, nil]
|
|
220
|
+
else
|
|
221
|
+
[nil, "Invalid text source."]
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def self.build_wcloud_argv(request, out_path, mask_path, font_path, exclude_path)
|
|
226
|
+
argv = ["-o", out_path]
|
|
227
|
+
argv += ["--width", request.width.to_s] if request.width && request.width > 0
|
|
228
|
+
argv += ["--height", request.height.to_s] if request.height && request.height > 0
|
|
229
|
+
argv += ["--seed", request.rng_seed.to_s] if request.rng_seed && request.rng_seed >= 0
|
|
230
|
+
argv += ["--mask", mask_path] if mask_path != ""
|
|
231
|
+
argv += ["--font", font_path] if font_path != ""
|
|
232
|
+
argv += ["--exclude-words", exclude_path] if exclude_path != ""
|
|
233
|
+
argv += ["--max-words", request.max_words.to_s] if request.max_words && request.max_words > 0
|
|
234
|
+
argv
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Run wcloud with argv (no shell). Optional stdin: string. Returns [stdout, stderr, exit_status].
|
|
238
|
+
def self.run_wcloud(wcloud_bin, argv, stdin: nil)
|
|
239
|
+
if stdin
|
|
240
|
+
stdout, stderr, status = Open3.capture3(wcloud_bin, *argv, stdin_data: stdin)
|
|
241
|
+
else
|
|
242
|
+
stdout, stderr, status = Open3.capture3(wcloud_bin, *argv)
|
|
243
|
+
end
|
|
244
|
+
[stdout.to_s, stderr.to_s, status.exitstatus]
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rakit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- rakit
|
|
@@ -131,6 +131,7 @@ files:
|
|
|
131
131
|
- lib/rakit/azure/dev_ops.rb
|
|
132
132
|
- lib/rakit/cli/file.rb
|
|
133
133
|
- lib/rakit/cli/markdown.rb
|
|
134
|
+
- lib/rakit/cli/word_cloud.rb
|
|
134
135
|
- lib/rakit/cli/word_count.rb
|
|
135
136
|
- lib/rakit/file.rb
|
|
136
137
|
- lib/rakit/gem.rb
|
|
@@ -140,6 +141,7 @@ files:
|
|
|
140
141
|
- lib/rakit/shell.rb
|
|
141
142
|
- lib/rakit/static_web_server.rb
|
|
142
143
|
- lib/rakit/task.rb
|
|
144
|
+
- lib/rakit/word_cloud.rb
|
|
143
145
|
- lib/rakit/word_count.rb
|
|
144
146
|
homepage: https://gitlab.com/gems/rakit
|
|
145
147
|
licenses:
|