ass_launcher 0.1.1.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.simplecov +1 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +122 -0
- data/Rakefile +10 -0
- data/ass_launcher.gemspec +32 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/ass_launcher/enterprise/binary_wrapper.rb +367 -0
- data/lib/ass_launcher/enterprise/cli/arguments_builder.rb +41 -0
- data/lib/ass_launcher/enterprise/cli/cli.spec +256 -0
- data/lib/ass_launcher/enterprise/cli/parameters.rb +289 -0
- data/lib/ass_launcher/enterprise/cli/spec_dsl/dsl_helpers.rb +66 -0
- data/lib/ass_launcher/enterprise/cli/spec_dsl.rb +209 -0
- data/lib/ass_launcher/enterprise/cli.rb +131 -0
- data/lib/ass_launcher/enterprise/ole/ole_binaries.rb +249 -0
- data/lib/ass_launcher/enterprise/ole/win32ole.rb +92 -0
- data/lib/ass_launcher/enterprise/ole.rb +188 -0
- data/lib/ass_launcher/enterprise/web_clients.rb +59 -0
- data/lib/ass_launcher/enterprise.rb +111 -0
- data/lib/ass_launcher/support/connection_string.rb +422 -0
- data/lib/ass_launcher/support/platforms.rb +232 -0
- data/lib/ass_launcher/support/shell/process_holder.rb +212 -0
- data/lib/ass_launcher/support/shell.rb +374 -0
- data/lib/ass_launcher/support/v8i_file.rb +66 -0
- data/lib/ass_launcher/support/v8i_section.rb +70 -0
- data/lib/ass_launcher/support.rb +9 -0
- data/lib/ass_launcher/version.rb +3 -0
- data/lib/ass_launcher.rb +6 -0
- metadata +202 -0
@@ -0,0 +1,422 @@
|
|
1
|
+
module AssLauncher
|
2
|
+
module Support
|
3
|
+
# Implement 1C connection string
|
4
|
+
# Mixin for connection string classes
|
5
|
+
# @note All connection string class have methods for get and set values
|
6
|
+
# of defined fields. Methods have name as fields but in downcase
|
7
|
+
# All fields defined for connection string class retutn {#fields}
|
8
|
+
# @example
|
9
|
+
# cs = AssLauncher::Support::\
|
10
|
+
# ConnectionString.new('File="\\fileserver\accounting.ib"')
|
11
|
+
# cs.is #-> :file
|
12
|
+
# cs.is? :file #-> true
|
13
|
+
# cs.usr = 'username'
|
14
|
+
# cs.pwd = 'password'
|
15
|
+
# cmd = "1civ8.exe enterprise #{cs.to_cmd}"
|
16
|
+
# run_result = AssLauncher::Support::Shell.run_ass(cmd)
|
17
|
+
module ConnectionString
|
18
|
+
class Error < StandardError; end
|
19
|
+
class ParseError < StandardError; end
|
20
|
+
# Commonn connection string fields
|
21
|
+
COMMON_FIELDS = %w(Usr Pwd LicDstr prmod Locale)
|
22
|
+
# Fields for server-infobase
|
23
|
+
SERVER_FIELDS = %w(Srvr Ref)
|
24
|
+
# Fields for file-infobase
|
25
|
+
FILE_FIELDS = %w(File)
|
26
|
+
# Fields for infobase published on http server
|
27
|
+
HTTP_FIELDS = %w(Ws)
|
28
|
+
HTTP_WEB_AUTH_FIELDS = %w(Wsn Wsp)
|
29
|
+
# Proxy fields for accsess to infobase published on http server via proxy
|
30
|
+
PROXY_FIELDS = %w(WspAuto WspSrv WspPort WspUser WspPwd)
|
31
|
+
# Fields for makes server-infobase
|
32
|
+
IB_MAKER_FIELDS = %w(DBMS DBSrvr DB
|
33
|
+
DBUID DBPwd SQLYOffs
|
34
|
+
CrSQLDB SchJobDn SUsr SPwd)
|
35
|
+
# Values for DBMS field
|
36
|
+
DBMS_VALUES = %w(MSSQLServer PostgreSQL IBMDB2 OracleDatabase)
|
37
|
+
|
38
|
+
# Analyzes connect string and build suitable class
|
39
|
+
# @param connstr (see parse)
|
40
|
+
# @return [Server | File | Http] instanse
|
41
|
+
def self.new(connstr)
|
42
|
+
case connstr
|
43
|
+
when /(\W|\A)File\s*=\s*"/i then File.new(parse(connstr))
|
44
|
+
when /(\W|\A)Srvr\s*=\s*"/i then Server.new(parse(connstr))
|
45
|
+
when /(\W|\A)Ws\s*=\s*"/i then Http.new(parse(connstr))
|
46
|
+
else
|
47
|
+
fail ParseError, "Uncknown connstr `#{connstr}'"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Parse connect string into hash.
|
52
|
+
# Connect string have format:
|
53
|
+
# 'Field1="Value";Field2="Value";'
|
54
|
+
# Quotes ' " ' in value of field escape as doble quote ' "" '.
|
55
|
+
# Fields name convert to downcase [Symbol]
|
56
|
+
# @example
|
57
|
+
# parse 'Field="""Value"""' -> {field: '"Value"'}
|
58
|
+
# @param connstr [String]
|
59
|
+
# @return [Hash]
|
60
|
+
def self.parse(connstr)
|
61
|
+
res = {}
|
62
|
+
connstr.split(';').each do |str|
|
63
|
+
str.strip!
|
64
|
+
res.merge!(parse_key_value str) unless str.empty?
|
65
|
+
end
|
66
|
+
res
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.parse_key_value(str)
|
70
|
+
fail ParseError, "Invalid string #{str}" unless\
|
71
|
+
/\A\s*(?<field>\w+)\s*=\s*"(?<value>.*)"\s*\z/i =~ str
|
72
|
+
{ field.downcase.to_sym => value.gsub('""', '"') }
|
73
|
+
end
|
74
|
+
private_class_method :parse_key_value
|
75
|
+
|
76
|
+
# Return type of connection string
|
77
|
+
# :file, :server, :http
|
78
|
+
# @return [Symbol]
|
79
|
+
def is
|
80
|
+
self.class.name.split('::').last.downcase.to_sym
|
81
|
+
end
|
82
|
+
|
83
|
+
# Check connection string for type :file, :server, :http
|
84
|
+
# @param symbol [Symvol]
|
85
|
+
# @example
|
86
|
+
# if cs.is? :file
|
87
|
+
# #do for connect to the file infobase
|
88
|
+
# else
|
89
|
+
# raise "#{cs.is} unsupport
|
90
|
+
# end
|
91
|
+
def is?(symbol)
|
92
|
+
is == symbol
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_hash
|
96
|
+
result = {}
|
97
|
+
fields.each do |f|
|
98
|
+
result[f.downcase.to_sym] = get_property(f)
|
99
|
+
end
|
100
|
+
result
|
101
|
+
end
|
102
|
+
|
103
|
+
def to_s(only_fields = nil)
|
104
|
+
only_fields ||= fields
|
105
|
+
result = ''
|
106
|
+
only_fields.each do |f|
|
107
|
+
result << "#{prop_to_s(f)};" unless get_property(f).to_s.empty?
|
108
|
+
end
|
109
|
+
result
|
110
|
+
end
|
111
|
+
|
112
|
+
# Convert connection string to array of 1C:Enterprise parameters.
|
113
|
+
# @return [Array] of 1C:Enterprise CLI parameters.
|
114
|
+
def to_args
|
115
|
+
to_args_common + to_args_private
|
116
|
+
end
|
117
|
+
|
118
|
+
def to_args_common
|
119
|
+
r = []
|
120
|
+
r += ['/N', usr] if usr
|
121
|
+
r += ['/P', pwd] if pwd
|
122
|
+
r += ['/UsePrivilegedMode', ''] if prmod.to_s == '1'
|
123
|
+
r += ['/L', locale] if locale
|
124
|
+
r
|
125
|
+
end
|
126
|
+
private :to_args_common
|
127
|
+
|
128
|
+
# Convert connection string to string of 1C:Enterprise parameters
|
129
|
+
# like /N"usr" /P"pwd" etc. See {#to_args}
|
130
|
+
# @return [String]
|
131
|
+
def to_cmd
|
132
|
+
r = ''
|
133
|
+
args = to_args
|
134
|
+
args.each_with_index do |v, i|
|
135
|
+
next unless i.even?
|
136
|
+
r << v
|
137
|
+
r << "\"#{args[i + 1]}\"" unless args[i + 1].to_s.empty?
|
138
|
+
r << ' '
|
139
|
+
end
|
140
|
+
r
|
141
|
+
end
|
142
|
+
|
143
|
+
# Fields required for new instance of connection string
|
144
|
+
def required_fields
|
145
|
+
self.class.required_fields
|
146
|
+
end
|
147
|
+
|
148
|
+
# All fields defined for connection string
|
149
|
+
def fields
|
150
|
+
self.class.fields
|
151
|
+
end
|
152
|
+
|
153
|
+
def self.included(base)
|
154
|
+
base.fields.each do |f|
|
155
|
+
base.send(:attr_accessor, f.downcase.to_sym)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
private
|
160
|
+
|
161
|
+
def _set_properties(hash)
|
162
|
+
hash.each do |key, value|
|
163
|
+
set_property(key, value)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def set_property(prop, value)
|
168
|
+
send("#{prop.downcase}=".to_sym, value)
|
169
|
+
end
|
170
|
+
|
171
|
+
def get_property(prop)
|
172
|
+
send(prop.downcase.to_sym)
|
173
|
+
end
|
174
|
+
|
175
|
+
def prop_to_s(prop)
|
176
|
+
"#{fields_to_hash[prop.downcase.to_sym]}="\
|
177
|
+
"\"#{get_property(prop).to_s.gsub('"', '""')}\""
|
178
|
+
end
|
179
|
+
|
180
|
+
def fields_to_hash
|
181
|
+
res = {}
|
182
|
+
fields.each do |f|
|
183
|
+
res[f.downcase.to_sym] = f
|
184
|
+
end
|
185
|
+
res
|
186
|
+
end
|
187
|
+
|
188
|
+
def required_fields_received?(received_fields)
|
189
|
+
(required_fields.map { |f| f.downcase.to_sym }\
|
190
|
+
& received_fields.keys.map { |k| k.downcase.to_sym }) == \
|
191
|
+
required_fields.map { |f| f.downcase.to_sym }
|
192
|
+
end
|
193
|
+
|
194
|
+
# Connection string for server-infobases
|
195
|
+
# @note (see ConnectionString)
|
196
|
+
class Server
|
197
|
+
# Simple class host:port
|
198
|
+
class ServerDescr
|
199
|
+
attr_reader :host, :port
|
200
|
+
|
201
|
+
# @param host [String] hostname
|
202
|
+
# @param port [String] port number
|
203
|
+
def initialize(host, port = nil)
|
204
|
+
@host = host.strip
|
205
|
+
@port = port.to_s.strip
|
206
|
+
end
|
207
|
+
|
208
|
+
# Parse sting <srv_string>
|
209
|
+
# @param srv_str [String] string like 'host:port,host:port'
|
210
|
+
# @return [Arry<ServerDescr>]
|
211
|
+
def self.parse(srv_str)
|
212
|
+
r = []
|
213
|
+
srv_str.split(',').each do |srv|
|
214
|
+
srv.strip!
|
215
|
+
r << new(* srv.chomp.split(':')) unless srv.empty?
|
216
|
+
end
|
217
|
+
r
|
218
|
+
end
|
219
|
+
|
220
|
+
# @return [String] formated 'host:port'
|
221
|
+
def to_s
|
222
|
+
"#{host}" + (port.empty? ? '' : ":#{port}")
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def self.fields
|
227
|
+
required_fields | COMMON_FIELDS | IB_MAKER_FIELDS
|
228
|
+
end
|
229
|
+
|
230
|
+
def self.required_fields
|
231
|
+
SERVER_FIELDS
|
232
|
+
end
|
233
|
+
|
234
|
+
include ConnectionString
|
235
|
+
|
236
|
+
def initialize(hash)
|
237
|
+
fail ConnectionString::Error unless required_fields_received?(hash)
|
238
|
+
_set_properties(hash)
|
239
|
+
end
|
240
|
+
|
241
|
+
# @return [Array<ServerDescr>]
|
242
|
+
def servers
|
243
|
+
@servers ||= []
|
244
|
+
end
|
245
|
+
|
246
|
+
def srvr=(str)
|
247
|
+
fail ArgumentError if str.empty?
|
248
|
+
@servers = ServerDescr.parse(str)
|
249
|
+
@srvr = str
|
250
|
+
end
|
251
|
+
|
252
|
+
def ref=(str)
|
253
|
+
fail ArgumentError if str.empty?
|
254
|
+
@ref = str
|
255
|
+
end
|
256
|
+
|
257
|
+
def srvr
|
258
|
+
servers.join(',')
|
259
|
+
end
|
260
|
+
|
261
|
+
def srvr_raw
|
262
|
+
@srvr
|
263
|
+
end
|
264
|
+
|
265
|
+
# Build string suitable for
|
266
|
+
# :createinfibase runmode
|
267
|
+
# @todo validte createinfibase params
|
268
|
+
def createinfobase_cmd
|
269
|
+
to_s
|
270
|
+
end
|
271
|
+
|
272
|
+
# Build string suitable for Ole objects connecting.
|
273
|
+
def to_ole_string
|
274
|
+
"#{to_s(fields - IB_MAKER_FIELDS)}"
|
275
|
+
end
|
276
|
+
|
277
|
+
# Build args array suitable for
|
278
|
+
# :createinfibase runmode
|
279
|
+
def createinfobase_args
|
280
|
+
[createinfobase_cmd]
|
281
|
+
end
|
282
|
+
|
283
|
+
# (see DBMS_VALUES)
|
284
|
+
def dbms=(value)
|
285
|
+
@dbms = valid_value(value, DBMS_VALUES)
|
286
|
+
end
|
287
|
+
|
288
|
+
def crsqldb=(value)
|
289
|
+
@crsqldb = yes_or_not(value)
|
290
|
+
end
|
291
|
+
|
292
|
+
def schjobdn=(value)
|
293
|
+
@schjobdn = yes_or_not(value)
|
294
|
+
end
|
295
|
+
|
296
|
+
def yes_or_not(value)
|
297
|
+
valid_value(value, %w(Y N))
|
298
|
+
end
|
299
|
+
private :yes_or_not
|
300
|
+
|
301
|
+
def valid_value(v, av)
|
302
|
+
fail ArgumentError, "Bad value #{v}. Accepted values are `#{av}'"\
|
303
|
+
unless av.map(&:downcase).include?(v.to_s.downcase)
|
304
|
+
v
|
305
|
+
end
|
306
|
+
private :valid_value
|
307
|
+
|
308
|
+
def to_args_private
|
309
|
+
['/S', "#{srvr}/#{ref}"]
|
310
|
+
end
|
311
|
+
private :to_args_private
|
312
|
+
end
|
313
|
+
|
314
|
+
# Connection string for file-infobases
|
315
|
+
# @note (see ConnectionString)
|
316
|
+
class File
|
317
|
+
def self.required_fields
|
318
|
+
FILE_FIELDS
|
319
|
+
end
|
320
|
+
|
321
|
+
def self.fields
|
322
|
+
required_fields | COMMON_FIELDS
|
323
|
+
end
|
324
|
+
|
325
|
+
include ConnectionString
|
326
|
+
|
327
|
+
def initialize(hash)
|
328
|
+
fail ConnectionString::Error unless required_fields_received?(hash)
|
329
|
+
_set_properties(hash)
|
330
|
+
end
|
331
|
+
|
332
|
+
def file=(str)
|
333
|
+
fail ArgumentError if str.empty?
|
334
|
+
@file = str
|
335
|
+
end
|
336
|
+
|
337
|
+
# Build string suitable for
|
338
|
+
# :createinfibase runmode
|
339
|
+
def createinfobase_cmd
|
340
|
+
"File=\"#{path.realdirpath.win_string}\""
|
341
|
+
end
|
342
|
+
|
343
|
+
# Build string suitable for Ole objects connecting.
|
344
|
+
def to_ole_string
|
345
|
+
"#{createinfobase_cmd};#{to_s(fields - ['File'])}"
|
346
|
+
end
|
347
|
+
|
348
|
+
# Build args array suitable for
|
349
|
+
# :createinfibase runmode
|
350
|
+
# Fucking 1C:
|
351
|
+
# - File="path" not work but work running as script
|
352
|
+
# - File='path' work correct
|
353
|
+
def createinfobase_args
|
354
|
+
["File='#{path.realdirpath.win_string}'"]
|
355
|
+
end
|
356
|
+
|
357
|
+
def path
|
358
|
+
AssLauncher::Support::Platforms.path(file)
|
359
|
+
end
|
360
|
+
|
361
|
+
# Convert connection string to array of 1C:Enterprise parameters.
|
362
|
+
# @return [Array] of 1C:Enterprise CLI parameters.
|
363
|
+
def to_args_private
|
364
|
+
['/F', path.realpath.to_s]
|
365
|
+
end
|
366
|
+
private :to_args_private
|
367
|
+
end
|
368
|
+
|
369
|
+
# Connection string for infobases published on http server
|
370
|
+
# @note (see ConnectionString)
|
371
|
+
class Http
|
372
|
+
def self.required_fields
|
373
|
+
HTTP_FIELDS
|
374
|
+
end
|
375
|
+
|
376
|
+
def self.fields
|
377
|
+
required_fields | COMMON_FIELDS | HTTP_WEB_AUTH_FIELDS | PROXY_FIELDS
|
378
|
+
end
|
379
|
+
|
380
|
+
include ConnectionString
|
381
|
+
|
382
|
+
def initialize(hash)
|
383
|
+
fail ConnectionString::Error unless required_fields_received?(hash)
|
384
|
+
_set_properties(hash)
|
385
|
+
end
|
386
|
+
|
387
|
+
def ws=(str)
|
388
|
+
fail ArgumentError if str.empty?
|
389
|
+
@ws = str
|
390
|
+
end
|
391
|
+
|
392
|
+
def uri
|
393
|
+
require 'uri'
|
394
|
+
uri = URI(ws)
|
395
|
+
uri.user = wsn
|
396
|
+
uri.password = wsp
|
397
|
+
uri
|
398
|
+
end
|
399
|
+
|
400
|
+
# Convert connection string to array of 1C:Enterprise parameters.
|
401
|
+
# @return [Array] of 1C:Enterprise CLI parameters.
|
402
|
+
def to_args_private
|
403
|
+
r = []
|
404
|
+
r += ['/WS', ws] if ws
|
405
|
+
r += ['/WSN', wsn] if wsn
|
406
|
+
r += ['/WSP', wsp] if wsp
|
407
|
+
to_args_private_proxy(r)
|
408
|
+
end
|
409
|
+
private :to_args_private
|
410
|
+
|
411
|
+
def to_args_private_proxy(r)
|
412
|
+
return r unless !wspauto && wspsrv
|
413
|
+
r += ['/Proxy', '', '-Psrv', wspsrv]
|
414
|
+
r += ['-PPort', wspport.to_s] if wspport
|
415
|
+
r += ['-PUser', wspuser] if wspuser
|
416
|
+
r += ['-PPwd', wsppwd] if wsppwd
|
417
|
+
r
|
418
|
+
end
|
419
|
+
end
|
420
|
+
end
|
421
|
+
end
|
422
|
+
end
|
@@ -0,0 +1,232 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'ffi'
|
4
|
+
|
5
|
+
module FFI
|
6
|
+
# Monkey patch of [FFI::Platform]
|
7
|
+
module Platform
|
8
|
+
IS_CYGWIN = is_os('cygwin')
|
9
|
+
|
10
|
+
def self.cygwin?
|
11
|
+
IS_CYGWIN
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.linux?
|
15
|
+
IS_LINUX
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module AssLauncher
|
21
|
+
module Support
|
22
|
+
# OS-specific things
|
23
|
+
# Mixin module help work with things as paths and env in other plases
|
24
|
+
# @example
|
25
|
+
# include AssLauncher::Support::Platforms
|
26
|
+
#
|
27
|
+
# if cigwin?
|
28
|
+
# #do if run in Cygwin
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# # Find env value on regex
|
32
|
+
# pf = platform.env[/program\s*files/i]
|
33
|
+
# return if pf.size == 0
|
34
|
+
#
|
35
|
+
# # Use #path
|
36
|
+
# p = platform.path(pf[0])
|
37
|
+
# p.exists?
|
38
|
+
#
|
39
|
+
# # Use #path_class
|
40
|
+
# platform.path_class.glob('C:/*').each do |path|
|
41
|
+
# path.exists?
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# # Use #glob directly
|
45
|
+
# platform.glob('C:/*').each do |path|
|
46
|
+
# path.exists?
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
#
|
50
|
+
module Platforms
|
51
|
+
# True if run in Cygwin
|
52
|
+
def cygwin?
|
53
|
+
FFI::Platform.cygwin?
|
54
|
+
end
|
55
|
+
module_function :cygwin?
|
56
|
+
|
57
|
+
# True if run in MinGW
|
58
|
+
def windows?
|
59
|
+
FFI::Platform.windows?
|
60
|
+
end
|
61
|
+
module_function :windows?
|
62
|
+
|
63
|
+
# True if run in Linux
|
64
|
+
def linux?
|
65
|
+
FFI::Platform.linux?
|
66
|
+
end
|
67
|
+
module_function :linux?
|
68
|
+
|
69
|
+
# Return module [Platforms] as helper
|
70
|
+
# @return [Platforms]
|
71
|
+
def platform
|
72
|
+
AssLauncher::Support::Platforms
|
73
|
+
end
|
74
|
+
private :platform
|
75
|
+
|
76
|
+
require 'pathname'
|
77
|
+
|
78
|
+
# Return suitable class
|
79
|
+
# @return [UnixPath | WinPath | CygPath]
|
80
|
+
def self.path_class
|
81
|
+
if cygwin?
|
82
|
+
PathnameExt::CygPath
|
83
|
+
elsif windows?
|
84
|
+
PathnameExt::WinPath
|
85
|
+
else
|
86
|
+
PathnameExt::UnixPath
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Return suitable class instance
|
91
|
+
# @return [UnixPath | WinPath | CygPath]
|
92
|
+
def self.path(string)
|
93
|
+
path_class.new(string)
|
94
|
+
end
|
95
|
+
|
96
|
+
# (see PathnameExt.glob)
|
97
|
+
def self.glob(p1, *args)
|
98
|
+
path_class.glob(p1, *args)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Parent for OS-specific *Path classes
|
102
|
+
# @todo TRANSLATE THIS:
|
103
|
+
#
|
104
|
+
# rubocop:disable AsciiComments
|
105
|
+
# @note
|
106
|
+
# Класс предназначен для унификации работы с путями ФС в различных
|
107
|
+
# ОС.
|
108
|
+
# ОС зависимые методы будут переопределены в классах потомках
|
109
|
+
# [UnixPath | WinPath | CygPath].
|
110
|
+
#
|
111
|
+
# Пути могут приходить из следующих источников:
|
112
|
+
# - из консоли - при этом в Cygwin путь вида '/cygdrive/c' будет
|
113
|
+
# непонятен за пределами Cygwin
|
114
|
+
# - из ENV - при этом путь \\\\host\\share будет непонятен в Unix
|
115
|
+
#
|
116
|
+
# Общая мысль в следующем:
|
117
|
+
# - пути приводятся к mixed_path - /cygwin/c -> C:/, C:\\ -> C:/,
|
118
|
+
# \\\\host\\share -> //host/share
|
119
|
+
# - переопределяется метод glob класса [Pathname] при этом метод в
|
120
|
+
# Cygwin будет иметь свою реализацию т.к. в cygwin
|
121
|
+
# Dirname.glob('C:/') вернет пустой массив,
|
122
|
+
# а Dirname.glob('/cygdrive/c') отработает правильно.
|
123
|
+
# rubocop:enable AsciiComments
|
124
|
+
class PathnameExt < Pathname
|
125
|
+
# Override constructor for lead path to (#mixed_path)
|
126
|
+
# @param string [String] - string of path
|
127
|
+
def initialize(string)
|
128
|
+
@raw = string.to_s.strip
|
129
|
+
super mixed_path(@raw)
|
130
|
+
end
|
131
|
+
|
132
|
+
# This is fix (bug or featere)? of [Pathname] method. Called in
|
133
|
+
# chiled clesses returns not childe class instance but returns
|
134
|
+
# [Pathname] instance
|
135
|
+
def +(other)
|
136
|
+
self.class.new(super(other).to_s)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Return mixed_path where delimiter is '/'
|
140
|
+
# @return [String]
|
141
|
+
def mixed_path(string)
|
142
|
+
string.tr('\\', '/')
|
143
|
+
end
|
144
|
+
private :mixed_path
|
145
|
+
|
146
|
+
# Return path suitable for windows apps. In Unix this method overridden
|
147
|
+
# @return [String]
|
148
|
+
def win_string
|
149
|
+
to_s.tr('/', '\\')
|
150
|
+
end
|
151
|
+
|
152
|
+
# Override (Pathname.glob) method for correct work with windows paths
|
153
|
+
# like a '\\\\host\\share', 'C:\\' and Cygwin paths like a '/cygdrive/c'
|
154
|
+
# @param (see Pathname.glob)
|
155
|
+
# @return [Array<PathnameExt>]
|
156
|
+
def self.glob(p1, *args)
|
157
|
+
super p1.tr('\\', '/'), *args
|
158
|
+
end
|
159
|
+
|
160
|
+
# Class for MinGW Ruby
|
161
|
+
class WinPath < PathnameExt; end
|
162
|
+
|
163
|
+
# Class for Unix Ruby
|
164
|
+
class UnixPath < PathnameExt
|
165
|
+
# (see PathnameExt#win_string)
|
166
|
+
def win_string
|
167
|
+
to_s
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Class for Cygwin Ruby
|
172
|
+
class CygPath < PathnameExt
|
173
|
+
# (cee PathnameExt#mixed_path)
|
174
|
+
def mixed_path(string)
|
175
|
+
cygpath(string, :m)
|
176
|
+
end
|
177
|
+
|
178
|
+
# (see PathnameExt.glob)
|
179
|
+
def self.glob(p1, *args)
|
180
|
+
super cygpath(p1, :u), *args
|
181
|
+
end
|
182
|
+
|
183
|
+
def self.cygpath(p1, flag)
|
184
|
+
fail ArgumentError, 'Only accepts :w | :m | :u flags'\
|
185
|
+
unless %w(w m u).include? flag.to_s
|
186
|
+
# TODO, extract shell call into Shell module
|
187
|
+
out = `cygpath -#{flag} #{p1.escape} 2>&1`.chomp
|
188
|
+
fail Shell::RunError, out unless exitstatus == 0
|
189
|
+
out
|
190
|
+
end
|
191
|
+
|
192
|
+
# TODO, extract shell call into Shell module
|
193
|
+
def self.exitstatus
|
194
|
+
# rubocop:disable all
|
195
|
+
fail Shell::Error, 'Unexpected $?.nil?' if $?.nil?
|
196
|
+
$?.exitstatus
|
197
|
+
# rubocop:enable all
|
198
|
+
end
|
199
|
+
private_class_method :exitstatus
|
200
|
+
|
201
|
+
def cygpath(p1, flag)
|
202
|
+
self.class.cygpath(p1, flag)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Return suitable class
|
208
|
+
# @return [UnixEnv | WinEnv | CygEnv]
|
209
|
+
def self.env
|
210
|
+
if cygwin?
|
211
|
+
CygEnv
|
212
|
+
elsif windows?
|
213
|
+
WinEnv
|
214
|
+
else
|
215
|
+
UnixEnv
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# Wrapper for ENV in Unix Ruby
|
220
|
+
class UnixEnv
|
221
|
+
# Return values ENV on regex
|
222
|
+
def self.[](regex)
|
223
|
+
ENV.map { |k, v| v if k =~ regex }.compact
|
224
|
+
end
|
225
|
+
end
|
226
|
+
# Wrapper for ENV in Cygwin Ruby
|
227
|
+
class CygEnv < UnixEnv; end
|
228
|
+
# Wrapper for ENV in MinGw Ruby
|
229
|
+
class WinEnv < UnixEnv; end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|