ass_launcher 0.1.1.alpha

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.
@@ -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