ass_launcher 0.1.1.alpha

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,209 @@
1
+ # encoding: utf-8
2
+
3
+ module AssLauncher
4
+ module Enterprise
5
+ module Cli
6
+ # DSL for describe 1C:Enterprise command-line interface
7
+ # @api public
8
+ module SpecDsl
9
+ require 'ass_launcher/enterprise/cli/spec_dsl/dsl_helpers'
10
+ require 'uri'
11
+ include DslHelpers
12
+
13
+ # Define 1C:Enterprise version for defined CLI specifications
14
+ # @param v [String] 1C:Enterprise verion string
15
+ def enterprise_version(v = '0')
16
+ @enterprise_version ||= Gem::Version.new(v)
17
+ end
18
+
19
+ # Describe run modes specifications
20
+ # @param mode [Symbol] 1C:Enterprise run mode.
21
+ # @param desc [String] description for run mode
22
+ # @param banner [String] bunner for usage
23
+ def describe_mode(mode, desc, banner)
24
+ fail "Undefined mode: #{mode}" unless defined_modes.include? mode
25
+ described_modes[mode] = { desc: _t(desc), banner: _t(banner) }
26
+ end
27
+
28
+ # Define CLI parameters group
29
+ # @param name [Symbol] group name
30
+ # @param desc [String] description for group
31
+ # @param priority [Fixnum] priority for parameters group for build
32
+ # help message
33
+ def define_group(name, desc, priority)
34
+ parameters_groups[name.to_sym] =
35
+ { desc: _t(desc), priority: priority }
36
+ end
37
+
38
+ # Binary matcher for 1C:Enterprise thick client for which CLI parameter
39
+ # defined
40
+ # @param v [String] version of 1C:Enterprise client
41
+ # @return [Cli::BinaryMatcher]
42
+ def thick_client(v = '>= 0')
43
+ BinaryMatcher.new(:thick, v)
44
+ end
45
+
46
+ # Binary matcher for 1C:Enterprise thin client for which CLI parameter
47
+ # defined
48
+ # @param (see #thick_client)
49
+ # @return (see #thick_client)
50
+ def thin_client(v = '>= 0')
51
+ BinaryMatcher.new(:thin, v)
52
+ end
53
+
54
+ # Binary matcher for 1C:Enterprise thin and thick clients for
55
+ # which CLI parameter defined
56
+ # @param (see #thick_client)
57
+ # @return (see #thick_client)
58
+ def all_client(v = '>= 0')
59
+ BinaryMatcher.new(:all, v)
60
+ end
61
+
62
+ # Block to define CLI parameters for run modes
63
+ # @param modes [Array<Symbol>] run modes wich CLI parameters defined
64
+ # @raise if passed invalid 1C:Enterprise run mode
65
+ # @raise if call without block
66
+ def mode(*modes, &block)
67
+ fail "Undefined modes #{modes}" if (defined_modes & modes).size == 0
68
+ fail 'method `mode` block required' unless block_given?
69
+ self.current_modes = modes
70
+ instance_eval(&block)
71
+ end
72
+
73
+ # Block to grouping CLI parameters into parameters group.
74
+ # Group must be defined as {#define_group}
75
+ # @param key [Symbol] group name
76
+ # @raise if passed undefined group
77
+ # @raise if call without block
78
+ def group(key, &block)
79
+ fail "Undefined parameters group #{key}"\
80
+ unless parameters_groups.key? key
81
+ fail 'method `group` block required' unless block_given?
82
+ self.current_group = key
83
+ instance_eval(&block)
84
+ end
85
+
86
+ # Build switch or chose list for CLI parameters clases:
87
+ # {Cli::Parameters::Switch} or {Cli::Parameters::Chose}
88
+ # @param options [Hash] +:key+ is argument for CLI parameter, +value+ is
89
+ # description for help message
90
+ def switch_list(**options)
91
+ options.each_key do |k|
92
+ options[k] = _t(options[k])
93
+ end
94
+ end
95
+ alias_method :chose_list, :switch_list
96
+
97
+ # Define {Cli::Parameters::Path} parameter and him subparameters.
98
+ # Subparameters defines in the block.
99
+ # @param name [String] name of 1C:Enterprise CLI parameter
100
+ # @param desc [String] description of 1C:Enterprise CLI parameter for
101
+ # build help message
102
+ # @param binary_matcher [Cli::BinaryMatcher] uses DSL:
103
+ # {#thick_client}, {#thin_client} or {#all_client}. If +nil+ uses
104
+ # {Cli::BinaryMatcher} for all 1C clients and all client's
105
+ # verions like returns {#all_client} method
106
+ # @param options (see Cli::Parameters::StringParam#initialize)
107
+ # @return [Cli::Parameters::Path]
108
+ def path(name, desc, binary_matcher = nil, **options, &block)
109
+ new_param(Parameters::Path, name, desc,
110
+ binary_matcher, **options, &block)
111
+ end
112
+
113
+ # Define {Cli::Parameters::StringParam} parameter and him subparameters.
114
+ # Subparameters defines in the block.
115
+ # @param (see #path)
116
+ # @return [Cli::Parameters::StringParam]
117
+ def string(name, desc, binary_matcher = nil, **options, &block)
118
+ new_param(Parameters::StringParam, name, desc,
119
+ binary_matcher, **options, &block)
120
+ end
121
+
122
+ # Define {Cli::Parameters::Flag} parameter and him subparameters.
123
+ # Subparameters defines in the block.
124
+ # @param (see #path)
125
+ # @return [Cli::Parameters::Flag]
126
+ def flag(name, desc, binary_matcher = nil, **options, &block)
127
+ new_param(Parameters::Flag, name, desc,
128
+ binary_matcher, **options, &block)
129
+ end
130
+
131
+ # Define {Cli::Parameters::Switch} parameter and him subparameters.
132
+ # Subparameters defines in the block.
133
+ # @note use helper {#switch_list} for build +:switch_list+ option
134
+ # @param (see #path)
135
+ # @return [Cli::Parameters::Switch]
136
+ def switch(name, desc, binary_matcher = nil, **options, &block)
137
+ new_param(Parameters::Switch, name, desc,
138
+ binary_matcher, **options, &block)
139
+ end
140
+
141
+ # Define {Cli::Parameters::Chose} parameter and him subparameters.
142
+ # Subparameters defines in the block.
143
+ # @note use helper {#chose_list} for build +:chose_list+ option
144
+ # @param (see #path)
145
+ # @return [Cli::Parameters::Chose]
146
+ def chose(name, desc, binary_matcher = nil, **options, &block)
147
+ new_param(Parameters::Chose, name, desc,
148
+ binary_matcher, **options, &block)
149
+ end
150
+
151
+ # Define {Cli::Parameters::StringParam} parameter suitable for
152
+ # validation URL argument. Subparameters defines in the block.
153
+ # @note It initialize +:value_validator+ option with +Proc+
154
+ # @param (see #path)
155
+ # @return [Cli::Parameters::StringParam]
156
+ def url(name, desc, binary_matcher = nil, **options, &block)
157
+ options[:value_validator] = url_value_validator(name)
158
+ string(name, desc, binary_matcher, **options, &block)
159
+ end
160
+
161
+ def url_value_validator(n)
162
+ proc do |value|
163
+ begin
164
+ URI(value)
165
+ rescue
166
+ raise ArgumentError,
167
+ "Invalid URL for parameter `#{n}': `#{value}'"
168
+ end
169
+ value
170
+ end
171
+ end
172
+ private :url_value_validator
173
+
174
+ # Define {Cli::Parameters::StringParam} parameter suitable for
175
+ # validation numeric argument. Subparameters defines in the block.
176
+ # @note It initialize +:value_validator+ option with +Proc+
177
+ # @param (see #path)
178
+ # @return [Cli::Parameters::StringParam]
179
+ def num(name, desc, binary_matcher = nil, **options, &block)
180
+ options[:value_validator] = num_value_validator(name)
181
+ string(name, desc, binary_matcher, **options, &block)
182
+ end
183
+
184
+ def num_value_validator(n)
185
+ proc do |value|
186
+ begin
187
+ Float(value)
188
+ rescue
189
+ raise ArgumentError,
190
+ "Invalid Number for parameter `#{n}': `#{value}'"
191
+ end
192
+ value
193
+ end
194
+ end
195
+ private :num_value_validator
196
+
197
+ # Stub for skipped parameter. Many 1C:Enterprise CLI parameters is not
198
+ # imprtant for describe in {Cli::CliSpec}. For define it fact, you can
199
+ # use this method.
200
+ # @todo may be registring skipped parameter for worning?
201
+ # @param (see #path)
202
+ # @return [nil]
203
+ def skip(name, desc = '', binary_matcher = nil, **options, &block)
204
+ # nop
205
+ end
206
+ end # SpecDsl
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,131 @@
1
+ # encoding: utf-8
2
+
3
+ module AssLauncher
4
+ class Configuration
5
+ # 1C Enterprise cli specifications text written on Cli::SpecDsl
6
+ def platform_cli_spec
7
+ @platform_cli_spec ||= Enterprise::Cli::CliSpec.load
8
+ end
9
+ end
10
+ module Enterprise
11
+ # @api private
12
+ # 1C:Enterprise cli api wrapper
13
+ module Cli
14
+ require 'ass_launcher/enterprise/cli/arguments_builder'
15
+ require 'ass_launcher/enterprise/cli/parameters'
16
+ require 'ass_launcher/enterprise/cli/spec_dsl'
17
+
18
+ # Run modes defined for 1C Enterprise binary client
19
+ DEFINED_MODES = [
20
+ :createinfobase,
21
+ :enterprise,
22
+ :designer
23
+ ].freeze
24
+
25
+ # Return suitable run_mode see {DEFINED_MODES} for
26
+ # 1c client
27
+ # @param cl [BinaryWrapper::ThinClient, BinaryWrapper::ThickClient]
28
+ # @return [Array<Symbol>]
29
+ def self.defined_modes_for(cl)
30
+ return [DEFINED_MODES[1]] if cl.instance_of? BinaryWrapper::ThinClient
31
+ return DEFINED_MODES if cl.instance_of? BinaryWrapper::ThickClient
32
+ end
33
+
34
+ # Load and 1C Enterprise cli specifications
35
+ # for buld cli api and cli api help
36
+ class CliSpec
37
+ def self.loader(binary, run_mode)
38
+ Class.new do
39
+ include AssLauncher::Enterprise::Cli::SpecDsl
40
+ attr_reader :run_mode, :binary_wrapper
41
+ def initialize(binary_wrapper, run_mode)
42
+ @binary_wrapper = binary_wrapper
43
+ @run_mode = run_mode
44
+ end
45
+ end.new(binary, run_mode)
46
+ end
47
+ private_class_method :loader
48
+
49
+ # @api private
50
+ # @todo In future, may be, should extract +cli.spec+ and use
51
+ # configurable +cli.spec+ path
52
+ def self.load
53
+ spec = File.read(File.expand_path('../cli/cli.spec',__FILE__))
54
+ end
55
+
56
+ # Max 1C Enterprise version
57
+ # for which defined parameters
58
+ # @return [Gem::Version]
59
+ attr_reader :enterprise_version
60
+ # Defined 1C Enterprise cli parameters
61
+ # @return [Parameters::ParamtersList]
62
+ attr_reader :parameters
63
+ # 1C Enterprise run modes descriptions for build cli api help
64
+ # @return (see Cli::SpecDsl#described_modes)
65
+ attr_reader :run_modes
66
+ # Description for 1C Enterprise cli parameters group for group
67
+ # parameters in cli help
68
+ # @return (see Cli::SpecDsl#described_modes)
69
+ attr_reader :groups
70
+
71
+ attr_reader :current_run_mode
72
+
73
+ attr_reader :current_binary_wrapper
74
+
75
+ # @api private
76
+ def initialize(parameters, modes, groups,
77
+ enterprise_version, binary_wrapper, run_mode)
78
+ @run_modes = modes.select { |k, v| binary_wrapper.run_modes.include? k }
79
+ @groups = groups
80
+ @enterprise_version = enterprise_version
81
+ @current_run_mode = run_mode
82
+ @current_binary_wrapper = binary_wrapper
83
+ @parameters = parameters
84
+ end
85
+
86
+ # Build suitable cli specifications for 1C Enterprise binary type,
87
+ # version and run mode
88
+ # @param binary [BinaryWrapper::ThinClient, BinaryWrapper::ThickClient]
89
+ # @param run_mode [Symbol] see {Cli::DEFINED_MODES}
90
+ def self.for(binary, run_mode)
91
+ l = loader(binary, run_mode)
92
+ l.instance_eval(AssLauncher.config.platform_cli_spec)
93
+ new(l.parameters,
94
+ l.described_modes,
95
+ l.parameters_groups,
96
+ l.enterprise_version,
97
+ binary,
98
+ run_mode)
99
+ end
100
+
101
+ def usage(run_mode = nil)
102
+ raise NotImplementedError
103
+ end
104
+ end
105
+
106
+ # @api private
107
+ class BinaryMatcher
108
+ attr_reader :client, :requirement
109
+ def initialize(client = :all, version = '>= 0')
110
+ @client = client.to_sym
111
+ @requirement = Gem::Requirement.new version
112
+ end
113
+
114
+ def match?(binary_wrapper)
115
+ match_client?(binary_wrapper) && match_version?(binary_wrapper)
116
+ end
117
+
118
+ private
119
+ def match_client?(bw)
120
+ return true if client == :all
121
+ client == bw.class.name.split('::').last.
122
+ to_s.downcase.gsub(/client$/,'').to_sym
123
+ end
124
+
125
+ def match_version?(bw)
126
+ requirement.satisfied_by? bw.version
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,249 @@
1
+ # encoding: utf-8
2
+ require 'ass_launcher/enterprise/ole/win32ole'
3
+ #
4
+ module AssLauncher
5
+ #
6
+ module Enterprise
7
+ #
8
+ module Ole
9
+ # Wrappers fore 1C Enterprise OLE servers
10
+ module OleBinaries
11
+ # @abstract
12
+ class AbstractAssOleBinary
13
+ include AssLauncher::Support::Platforms
14
+ # @return [Gem::Version::Requirement]
15
+ attr_reader :requirement
16
+ # @param requirement [Gem::Version::Requirement] version of 1C Ole
17
+ # server
18
+ def initialize(requirement)
19
+ fail NotImplementedError, 'WIN32OLE undefined for this machine'\
20
+ if linux?
21
+ @requirement = Gem::Version::Requirement.new(requirement)
22
+ end
23
+
24
+ # @return [WIN32OLE] 1C Ole server object
25
+ def ole
26
+ @ole ||= new_ole
27
+ end
28
+
29
+ def new_ole
30
+ reg
31
+ WIN32OLE.new(prog_id)
32
+ end
33
+ private :new_ole
34
+
35
+ def v8x
36
+ instaled_version.to_s.split('.').slice(0, 2).join('')
37
+ end
38
+ private :v8x
39
+
40
+ def instaled_version
41
+ return binary_wrapper.version if binary_wrapper
42
+ end
43
+ alias_method :version, :instaled_version
44
+
45
+ # @return [AssLauncher::Enterprise::BinaryWrapper]
46
+ def binary_wrapper
47
+ @binary_wrapper ||= _binary_wrapper
48
+ end
49
+ protected :binary_wrapper
50
+
51
+ def _binary_wrapper
52
+ fail 'Abstract method call'
53
+ end
54
+ private :_binary_wrapper
55
+
56
+ def registred_version
57
+ fail NotImplementedError # FIXME: not find object in WinReg
58
+ end
59
+ private :registred_version
60
+
61
+ # Return +true+ if 1C Ole object instaled
62
+ def instaled?
63
+ return false unless version
64
+ requirement.satisfied_by?(version) && File.file?(path.to_s)
65
+ end
66
+
67
+ def registred?
68
+ # FIXME: always return false and not find object in WinReg
69
+ # registred_version == version
70
+ false # FIXME
71
+ end
72
+ private :registred?
73
+
74
+ # Register Ole server
75
+ def reg
76
+ return true if registred?
77
+ fail "Platform version `#{requirement}' not instaled."\
78
+ unless instaled?
79
+ reg_server
80
+ end
81
+
82
+ def reg_server
83
+ fail 'Abstract method call'
84
+ end
85
+ private :reg_server
86
+
87
+ # Unregister Ole server
88
+ def unreg
89
+ return true unless registred?
90
+ fail "Platform version `#{requirement}' not instaled."\
91
+ unless instaled?
92
+ unreg_server
93
+ end
94
+
95
+ def unreg_server
96
+ fail 'Abstract method call'
97
+ end
98
+ private :unreg_server
99
+
100
+ def path
101
+ @path ||= _path
102
+ end
103
+ protected :path
104
+
105
+ def binary
106
+ fail 'Abstract method call'
107
+ end
108
+ protected :binary
109
+
110
+ def _path
111
+ return unless binary_wrapper
112
+ platform.path(File.join(binary_wrapper.path.dirname.to_s, binary))
113
+ end
114
+ private :_path
115
+
116
+ def clsid
117
+ clsids[v8x]
118
+ end
119
+ protected :clsid
120
+
121
+ def clsids
122
+ fail 'Abstract method call'
123
+ end
124
+ protected :clsids
125
+ end
126
+
127
+ # Wrapper for v8x.COMConnector inproc OLE server
128
+ # @note It work not correct. If old version ole object is loded in
129
+ # memory new registred version will be ignored.
130
+ class COMConnector < AbstractAssOleBinary
131
+ require 'english'
132
+ BINARY = 'comcntr.dll'
133
+ def binary
134
+ BINARY
135
+ end
136
+ private :binary
137
+
138
+ def prog_id
139
+ "v#{v8x}.COMConnector"
140
+ end
141
+ private :prog_id
142
+
143
+ def clsids
144
+ { '83' => '{181E893D-73A4-4722-B61D-D604B3D67D47}',
145
+ '82' => '{2B0C1632-A199-4350-AA2D-2AEE3D2D573A}',
146
+ '81' => '{48EE4DBA-DE11-4af2-83B9-1F7FD6B6B3E3}'
147
+ }
148
+ end
149
+ private :clsids
150
+
151
+ def _binary_wrapper
152
+ Enterprise.thick_clients(requirement.to_s).last
153
+ end
154
+ private :_binary_wrapper
155
+
156
+ # @note It work not correct. If old version ole object is loded in
157
+ # memory new registred version will be ignored.
158
+ def reg_server
159
+ fail_reg_unreg_server('register', reg_unreg_server('i'))
160
+ end
161
+ private :reg_server
162
+
163
+ def unreg_server
164
+ fail_reg_unreg_server('unregister', reg_unreg_server('u'))
165
+ end
166
+ private :unreg_server
167
+
168
+ def reg_unreg_server(mode)
169
+ `regsvr32 /#{mode} /s "#{path.win_string}"`
170
+ childe_status
171
+ end
172
+ private :reg_unreg_server
173
+
174
+ def childe_status
175
+ $CHILD_STATUS
176
+ end
177
+ private :childe_status
178
+
179
+ def fail_reg_unreg_server(message, status)
180
+ fail "Failure #{message} `#{path.win_string}' #{status}"\
181
+ unless status.success?
182
+ status
183
+ end
184
+ private :fail_reg_unreg_server
185
+ end
186
+
187
+ # Wrapper for v8x.Application standalone OLE server
188
+ class ThickApplication < AbstractAssOleBinary
189
+ BINARY = '1cv8.exe'
190
+ def binary
191
+ BINARY
192
+ end
193
+ private :binary
194
+
195
+ def prog_id
196
+ "v#{v8x}.Application"
197
+ end
198
+ private :prog_id
199
+
200
+ def _binary_wrapper
201
+ Enterprise.thick_clients(requirement.to_s).last
202
+ end
203
+ private :_binary_wrapper
204
+
205
+ def reg_server
206
+ run_as_enterprise ['/regserver']
207
+ end
208
+ private :reg_server
209
+
210
+ def unreg_server
211
+ run_as_enterprise ['/unregserver']
212
+ end
213
+ private :unreg_server
214
+
215
+ def run_as_enterprise(args)
216
+ binary_wrapper.command(:enterprise, args)
217
+ .run.wait.result.verify!
218
+ end
219
+ private :run_as_enterprise
220
+ end
221
+
222
+ # Wrapper for v8xc.Application standalone OLE server
223
+ class ThinApplication < ThickApplication
224
+ BINARY = '1cv8c.exe'
225
+ def binary
226
+ BINARY
227
+ end
228
+ private :binary
229
+
230
+ def prog_id
231
+ "v#{v8x}c.Application"
232
+ end
233
+ private :prog_id
234
+
235
+ def _binary_wrapper
236
+ Enterprise.thin_clients(requirement.to_s).last
237
+ end
238
+ private :_binary_wrapper
239
+
240
+ def run_as_enterprise(args)
241
+ binary_wrapper.command(args)
242
+ .run.wait.result.verify!
243
+ end
244
+ private :run_as_enterprise
245
+ end
246
+ end
247
+ end
248
+ end
249
+ end
@@ -0,0 +1,92 @@
1
+ # encoding: utf-8
2
+
3
+ # Monkey patch for WIN32OLE class
4
+ # - Define dummy class for Linux. Fail +NotImplementedError+ in constructor.
5
+ #
6
+ # - Patch for have chanse to close connection with 1C infobase in class
7
+ # {AssLauncher::Enterprise::Ole::IbConnection IBConnector}. For this reason
8
+ # overload
9
+ # method +WIN32OLE#method_missing+ and hold Ole object refs retuned from ole
10
+ # method into {#__objects__} array.
11
+ # {AssLauncher::Enterprise::Ole::IbConnection IBConnector}
12
+ # when close connection call
13
+ # {#\_\_ass_ole_free\_\_} and try to ole_free for all in {#__objects__} array.
14
+ # @see AssLauncher::Enterprise::Ole::IbConnection#__close__
15
+ class WIN32OLE
16
+ # :nocov:
17
+ if AssLauncher::Support::Platforms.linux?
18
+ def initialize(*_)
19
+ fail NotImplementedError, 'WIN32OLE undefined for this machine'
20
+ end
21
+
22
+ # For tests
23
+ def method_missing(*args)
24
+ args[1]
25
+ end
26
+ else
27
+ require 'win32ole'
28
+ @win32ole_loaded = true # for tests zonde
29
+ end
30
+ # :nocov:
31
+
32
+ # Hold created Ole objects
33
+ # @return [Array]
34
+ # @api private
35
+ def __objects__
36
+ @__objects__ ||= []
37
+ end
38
+
39
+ # @note WIN32OLE avtomaticaly wrapp Ruby objects into WIN32OLE class
40
+ # when they passed as parameter.
41
+ # When passed object retuns on Ruby side he will keep as WIN32OLE
42
+ #
43
+ # True if real object is Ruby object
44
+ def __ruby__?
45
+ ole_respond_to? :object_id
46
+ end
47
+
48
+ # @note (see #__ruby__?)
49
+ # Return Ruby object wrapped in to WIN32OLE. If {#__ruby__?} is *false*
50
+ # return *self*
51
+ # @return [Object, self]
52
+ def __real_obj__
53
+ return self unless __ruby__?
54
+ ObjectSpace._id2ref(invoke :object_id)
55
+ end
56
+
57
+ # @api private
58
+ # Call ole_free for all created chiled Ole objects then free self
59
+ def __ass_ole_free__
60
+ @__objects__ = __ass_ole_free_objects__
61
+ self.class.__ass_ole_free__(self)
62
+ end
63
+
64
+ # Free created chiled Ole objects
65
+ def __ass_ole_free_objects__
66
+ __objects__.each do |o|
67
+ o.send :__ass_ole_free__ if o.is_a? WIN32OLE
68
+ end
69
+ nil
70
+ end
71
+ private :__ass_ole_free_objects__
72
+
73
+ # @api private
74
+ # Try call ole_free for ole object
75
+ # @param obj [WIN32OLE] object for free
76
+ def self.__ass_ole_free__(obj)
77
+ return if WIN32OLE.ole_reference_count(obj) <= 0
78
+ obj.ole_free
79
+ end
80
+
81
+ # @!method method_missing(*args)
82
+ # overload {WIN32OLE#method_missing} and hold Ole object into
83
+ # {#__objects__} array if called Ole method return Ole object
84
+ old_method_missing = instance_method(:method_missing)
85
+ define_method(:method_missing) do |*args|
86
+ # :nocov:
87
+ o = old_method_missing.bind(self).call(*args)
88
+ __objects__ << o if o.is_a? WIN32OLE
89
+ o
90
+ # :nocov:
91
+ end
92
+ end