ass_updater 0.1.1
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 +7 -0
- data/.gitignore +9 -0
- data/.rubocop.yml +13 -0
- data/.travis.yml +11 -0
- data/Gemfile +4 -0
- data/README.md +122 -0
- data/Rakefile +16 -0
- data/ass_updater.gemspec +30 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/ass_updater.rb +181 -0
- data/lib/ass_updater/ass_version.rb +107 -0
- data/lib/ass_updater/http.rb +79 -0
- data/lib/ass_updater/update_distrib.rb +89 -0
- data/lib/ass_updater/update_history.rb +99 -0
- data/lib/ass_updater/update_info.rb +39 -0
- data/lib/ass_updater/update_info_service.rb +38 -0
- data/lib/ass_updater/version.rb +4 -0
- metadata +159 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e0034241f1fb0697994f2b1c81db89bc645aae7e
|
4
|
+
data.tar.gz: f25a9d22248cd218f570cef410f7569ac8b832f1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8b6da7b420b4395f0064c9ef8b0d6b956a6094f4e478cb0b5a64daa59166653e96371e386ac22d2e99d2a93722acd6c0afba61abf15969c2122b223fa4a53081
|
7
|
+
data.tar.gz: 9fc79fa2116717b86d55c3a284cc930e4bf74b67ba062b603977a1813a801183c84996824bfc1488fe2c7d7c86ea252a8e4c63f285a89b01d44a64921530c621
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
[](https://travis-ci.org/leoniv/ass_updater)
|
2
|
+
[](http://inch-ci.org/github/leoniv/ass_updater)
|
3
|
+
[](https://codeclimate.com/github/leoniv/ass_updater)
|
4
|
+
|
5
|
+
# AssUpdater
|
6
|
+
|
7
|
+
This gem make easy monitoring of release and to get 1C configuration's updates
|
8
|
+
from service http://dounloads.v8.1c.ru.
|
9
|
+
For read more about 1C configurations see http://v8.1c.ru
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'ass_updater'
|
17
|
+
```
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
$ bundle
|
22
|
+
|
23
|
+
Or install it yourself as:
|
24
|
+
|
25
|
+
$ gem install ass_updater
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
### Monitoring release configuration's update
|
30
|
+
|
31
|
+
Write your script `update_monitor.rb` like this:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
require 'ass_updater'
|
35
|
+
|
36
|
+
CONFIGS_ON_SUPPORT = ['HRM 3.0',
|
37
|
+
'Accounting 3.0',
|
38
|
+
'Accounting 2.0',
|
39
|
+
'AccountingKz 2.0'
|
40
|
+
]
|
41
|
+
def tmplt_root
|
42
|
+
# Default path for windows:
|
43
|
+
File.join ENV['APPDATA'].gsub('\\', '/'), '1c', '1cv8', 'tmplts'
|
44
|
+
# Or you can set other value
|
45
|
+
end
|
46
|
+
|
47
|
+
def secrets(conf_code_name)
|
48
|
+
case conf_code_name
|
49
|
+
when 'AccountingKz' then ['user_kz', 'pass_kz']
|
50
|
+
else ['user','pass']
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def new_updates(updater)
|
55
|
+
updater.update_history.all_versions.map do |v|
|
56
|
+
max = updater.instaled_versions(tmplt_root).max ||\
|
57
|
+
AssUpdater::AssVersion.zerro_version
|
58
|
+
v if v > max
|
59
|
+
end.compact
|
60
|
+
end
|
61
|
+
|
62
|
+
def send_mail(subject, message, attachments=nil)
|
63
|
+
#FIXME puts your code
|
64
|
+
puts "#{subject} #{message} #{attachments}"
|
65
|
+
end
|
66
|
+
|
67
|
+
def success_report(distrib)
|
68
|
+
subject = '1C update monitor report'
|
69
|
+
message = "Reseived update for '#{distrib.ass_updater.conf_code_name}' "\
|
70
|
+
"version: #{distrib.version}"
|
71
|
+
attachments = distrib.file_list.map do |file|
|
72
|
+
file if file =~ /(.*readme.*|.*новое.*\.htm)/i
|
73
|
+
end.compact
|
74
|
+
[subject,message,attachments]
|
75
|
+
end
|
76
|
+
|
77
|
+
def error_report(e)
|
78
|
+
subject = '1C update monitor report'
|
79
|
+
message = "Error: #{e.to_s}"
|
80
|
+
[subject, message]
|
81
|
+
end
|
82
|
+
|
83
|
+
CONFIGS_ON_SUPPORT.each do |i|
|
84
|
+
conf_code_name, conf_redaction = *i.split(' ')
|
85
|
+
updater = AssUpdater.new(conf_code_name,conf_redaction)
|
86
|
+
begin
|
87
|
+
updater.get_updates(*secrets(conf_code_name),
|
88
|
+
new_updates(updater),
|
89
|
+
tmplt_root) do |distrib|
|
90
|
+
send_mail *success_report(distrib)
|
91
|
+
end
|
92
|
+
rescue Exception => e
|
93
|
+
send_mail *error_report(e)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
and put string into `crontab`:
|
99
|
+
|
100
|
+
0 */6 * * * ruby your_path/update_monitor.rb
|
101
|
+
|
102
|
+
### Get required upadates
|
103
|
+
|
104
|
+
If you whant get all updates for your 1C infobase from current version to last release:
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
require 'ass_updater'
|
108
|
+
|
109
|
+
updater = AssUpdater.new 'HRM', '3.0'
|
110
|
+
|
111
|
+
updater.get_updates('user',
|
112
|
+
'password',
|
113
|
+
updater.required_versions_for_update(@curen_version),
|
114
|
+
@tmplt_root) do |disrib|
|
115
|
+
puts "Reseived update #{disrib.version}"
|
116
|
+
end
|
117
|
+
```
|
118
|
+
|
119
|
+
## Contributing
|
120
|
+
|
121
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/leoniv/ass_updater.
|
122
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rake/testtask"
|
3
|
+
|
4
|
+
Rake::TestTask.new(:test) do |t|
|
5
|
+
t.libs << "test"
|
6
|
+
t.libs << "lib"
|
7
|
+
t.test_files = FileList['test/**/*_test.rb']
|
8
|
+
end
|
9
|
+
|
10
|
+
task :default => :test
|
11
|
+
|
12
|
+
desc 'Run tests with simplecov'
|
13
|
+
task :test_with_simplecov do
|
14
|
+
ENV["SIMPLECOV"] = 'YES'
|
15
|
+
Rake::Task["test"].invoke
|
16
|
+
end
|
data/ass_updater.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ass_updater/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ass_updater"
|
8
|
+
spec.version = AssUpdater::VERSION
|
9
|
+
spec.authors = ["Leonid Vlasov"]
|
10
|
+
spec.email = ["leoniv.vlasov@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Wrapper for 1C configuration updates service}
|
13
|
+
spec.description = spec.summary
|
14
|
+
spec.homepage = "https://github.com/leoniv/ass_updater"
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_dependency "rubyzip", "~> 1.1"
|
23
|
+
spec.add_dependency "nori", "~> 2.6"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
26
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
+
spec.add_development_dependency "minitest"
|
28
|
+
spec.add_development_dependency "pry"
|
29
|
+
spec.add_development_dependency "simplecov"
|
30
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "ass_updater"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "pry"
|
14
|
+
Pry.start
|
data/bin/setup
ADDED
data/lib/ass_updater.rb
ADDED
@@ -0,0 +1,181 @@
|
|
1
|
+
#-- incoding utf-8
|
2
|
+
require 'zip'
|
3
|
+
require 'nori'
|
4
|
+
require 'ass_updater/version'
|
5
|
+
|
6
|
+
# AssUpdater - make easy download and install updates for 1C configuration from
|
7
|
+
# service http://dounloads.v8.1c.ru. For read more about 1C configurations
|
8
|
+
# visit site http://v8.1c.ru
|
9
|
+
class AssUpdater
|
10
|
+
class Error < StandardError; end
|
11
|
+
|
12
|
+
require 'ass_updater/ass_version'
|
13
|
+
require 'ass_updater/http'
|
14
|
+
require 'ass_updater/update_info_service'
|
15
|
+
require 'ass_updater/update_info'
|
16
|
+
require 'ass_updater/update_history'
|
17
|
+
require 'ass_updater/update_distrib'
|
18
|
+
|
19
|
+
PLATFORM_VERSIONS = { :"8.2" => '8.2', :"8.3" => '8.3' }
|
20
|
+
KNOWN_CONF_CODENAME = { HRM: 'Зарплата и управление персоналом',
|
21
|
+
Accounting: 'Бухгалтерия предприятия',
|
22
|
+
AccountingKz: 'Бухгалтерия для Казахстана' }
|
23
|
+
UPDATEREPO_BASE = 'http://downloads.v8.1c.ru/tmplts/'
|
24
|
+
UPDATEINFO_BASE = 'http://downloads.1c.ru/ipp/ITSREPV/V8Update/Configs/'
|
25
|
+
UPD11_ZIP = 'v8upd11.zip'
|
26
|
+
|
27
|
+
# See arguments of {#initialize}
|
28
|
+
# @return [String]
|
29
|
+
attr_reader :conf_code_name, :conf_redaction, :platform_version
|
30
|
+
# Object for access to 1C services. It's public for configure http connection.
|
31
|
+
# @return [AssUpdater::HTTP]
|
32
|
+
attr_accessor :http
|
33
|
+
|
34
|
+
# @param conf_code_name [String] code name of configuration
|
35
|
+
# @param conf_redaction [String] redaction is major version nuber of
|
36
|
+
# configuration. See {AssUpdater::AssVersion#redaction}
|
37
|
+
# @param platform_version [String] major version namber of target platform
|
38
|
+
# 1C:Enterprese.
|
39
|
+
# @yield self. It's good place for configure http object. See
|
40
|
+
# {AssUpdater::HTTP}
|
41
|
+
# @raise [AssUpdater::Error] if given invalid <conf_redaction> or
|
42
|
+
# <platform_version>
|
43
|
+
def initialize(conf_code_name,
|
44
|
+
conf_redaction,
|
45
|
+
platform_version = PLATFORM_VERSIONS.keys.last
|
46
|
+
)
|
47
|
+
@conf_code_name = conf_code_name
|
48
|
+
@http = AssUpdater::HTTP.new
|
49
|
+
@conf_redaction = AssUpdater.valid_redaction(conf_redaction)
|
50
|
+
@platform_version = AssUpdater.valid_platform_version(platform_version)
|
51
|
+
yield self if block_given?
|
52
|
+
end
|
53
|
+
|
54
|
+
# Return info about last configuration release from file UpdInfo.txt
|
55
|
+
# @note (see AssUpdater::UpdateInfo)
|
56
|
+
# @return [AssUpdater::UpdateInfo]
|
57
|
+
def update_info
|
58
|
+
@update_info ||= AssUpdater::UpdateInfo.new(self)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Return updates history from v8upd11.xml
|
62
|
+
# @note (see AssUpdater::UpdateHistory)
|
63
|
+
# @return [Hash]
|
64
|
+
def update_history
|
65
|
+
@update_history ||= AssUpdater::UpdateHistory.new(self)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Evaluate versions required for update configuration
|
69
|
+
# from version <from_ver> to version <to_ver>. Return array
|
70
|
+
# iclude <to_ver> and exclude <from_ver> If called whithout
|
71
|
+
# arguments return versions required for update from version
|
72
|
+
# '0.0.0.0' to last release.
|
73
|
+
# @param from_ver [String,AssUpdater::AssVersion] if nil from_ver set to
|
74
|
+
# '0.0.0.0'
|
75
|
+
# @param to_ver [String,AssUpdater::AssVersion] if nill to_ver set to last
|
76
|
+
# release
|
77
|
+
# @return [Array<AssUpdater::AssVersion>]
|
78
|
+
# @raise [ArgumentError] if <from_ver> more then <to_ver>
|
79
|
+
def required_versions_for_update(from_ver = nil, to_ver = nil)
|
80
|
+
from_ver = AssUpdater::AssVersion.new(from_ver)
|
81
|
+
to_ver = AssUpdater::AssVersion.new(to_ver || update_history.max_version)
|
82
|
+
if from_ver >= to_ver
|
83
|
+
fail ArgumentError, 'from_ver must be less than to_ver'
|
84
|
+
end
|
85
|
+
r = []
|
86
|
+
c_ver = to_ver
|
87
|
+
loop do
|
88
|
+
r << c_ver
|
89
|
+
targets = update_history.target c_ver
|
90
|
+
break if targets.size == 0 || targets.index(from_ver)
|
91
|
+
c_ver = targets.min
|
92
|
+
end
|
93
|
+
r
|
94
|
+
end
|
95
|
+
|
96
|
+
# (see AssUpdater::UpdateDistrib)
|
97
|
+
# @note (see AssUpdater::UpdateDistrib#get)
|
98
|
+
# @param user (see AssUpdater::UpdateDistrib#get)
|
99
|
+
# @param password (see AssUpdater::UpdateDistrib#get)
|
100
|
+
# @param version (see AssUpdater::UpdateDistrib#initialize)
|
101
|
+
# @param tmplt_root (see AssUpdater::UpdateDistrib#initialize)
|
102
|
+
# @return (see AssUpdater::UpdateDistrib#get)
|
103
|
+
def get_update(user, password, version, tmplt_root)
|
104
|
+
distrib = new_update_distrib(version, tmplt_root)
|
105
|
+
distrib.get(user, password)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Get updates included in array <versions>. See {#get_update}
|
109
|
+
# @param user (see #get_update)
|
110
|
+
# @param password (see #get_update)
|
111
|
+
# @param versions [Array<String,AssUpdater::AssVersion>]
|
112
|
+
# @param tmplt_root (see #get_update)
|
113
|
+
# @return [Array<AssUpdater::UpdateDistrib>] returned {#get_update}
|
114
|
+
# @yield [AssUpdater::UpdateDistrib] for each getted distrib
|
115
|
+
def get_updates(user, password, versions, tmplt_root)
|
116
|
+
r = []
|
117
|
+
versions.each do |version|
|
118
|
+
r << get_update(user, password, version, tmplt_root)
|
119
|
+
yield r.last if block_given?
|
120
|
+
end
|
121
|
+
r
|
122
|
+
end
|
123
|
+
|
124
|
+
# Return versions all instaled updates finded in 1C templates directory
|
125
|
+
# <tmplt_root>
|
126
|
+
# @param tmplt_root (see #get_update)
|
127
|
+
# @return [Array<AssUpdater::AssVersion>]
|
128
|
+
def instaled_versions(tmplt_root)
|
129
|
+
(Dir.entries(conf_distribs_local_path(tmplt_root)).map do |e|
|
130
|
+
next if e == '.' || e == '..'
|
131
|
+
begin
|
132
|
+
v = AssUpdater::AssVersion.new(e.split('_').join('.'))
|
133
|
+
v if v.redaction == conf_redaction
|
134
|
+
rescue ArgumentError
|
135
|
+
nil
|
136
|
+
end
|
137
|
+
end).compact
|
138
|
+
end
|
139
|
+
|
140
|
+
# Return all instaled updates findet in 1C templates directory
|
141
|
+
# @note return distirbs present in {#update_history} only
|
142
|
+
# @param tmplt_root (see #get_update)
|
143
|
+
# @return [Array<AssUpdater::UpdateDistrib>]
|
144
|
+
def instaled_distribs(tmplt_root)
|
145
|
+
instaled_versions(tmplt_root).map do |v|
|
146
|
+
begin
|
147
|
+
new_update_distrib(v, tmplt_root)
|
148
|
+
rescue AssUpdater::Error
|
149
|
+
nil
|
150
|
+
end
|
151
|
+
end.compact
|
152
|
+
end
|
153
|
+
|
154
|
+
# Wrapper return UpdateDistrib object
|
155
|
+
# @param version (see #get_update)
|
156
|
+
# @param tmplt_root (see #get_update)
|
157
|
+
# @return [AssUpdater::UpdateDistrib]
|
158
|
+
def new_update_distrib(version, tmplt_root)
|
159
|
+
AssUpdater::UpdateDistrib.new(version, tmplt_root, self)
|
160
|
+
end
|
161
|
+
|
162
|
+
private
|
163
|
+
|
164
|
+
def conf_distribs_local_path(tmplt_root)
|
165
|
+
File.join(tmplt_root, '1c', conf_code_name)
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.valid_platform_version(v)
|
169
|
+
unless PLATFORM_VERSIONS.key?(v.to_sym)
|
170
|
+
fail AssUpdater::Error,
|
171
|
+
"Invalid platform_version `#{v}'."\
|
172
|
+
"Support #{PLATFORM_VERSIONS.keys.join(' | ')} versions only."
|
173
|
+
end
|
174
|
+
PLATFORM_VERSIONS[v.to_sym]
|
175
|
+
end
|
176
|
+
|
177
|
+
def self.valid_redaction(r)
|
178
|
+
fail AssUpdater::Error, "Invalid redaction #{r}" unless r =~ /\d\.\d/
|
179
|
+
r
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
class AssUpdater
|
2
|
+
# Class implement 1C version numbering. 1C version consist from 4 digt group.
|
3
|
+
# Major 1st and 2nd group called *Redaction*.
|
4
|
+
class AssVersion
|
5
|
+
# Value of digit group
|
6
|
+
# @return [Fixrnum]
|
7
|
+
attr_reader :_1, :_2, :_3, :_4
|
8
|
+
|
9
|
+
class << self
|
10
|
+
# Return zerro vesion number '0.0.0.0'
|
11
|
+
# @return [AssUpdater::AssVersion]
|
12
|
+
def zerro_version
|
13
|
+
new('0.0.0.0')
|
14
|
+
end
|
15
|
+
|
16
|
+
# Convert [Array<String>] to [Array<AssUpdater::AssVersion>]
|
17
|
+
# @return [Array<AssUpdater::AssVersion>]
|
18
|
+
def convert_array(a)
|
19
|
+
a.map do |i|
|
20
|
+
new(i)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return true if it is zerro version see
|
26
|
+
# {.zerro_version}
|
27
|
+
def zerro?
|
28
|
+
to_s == '0.0.0.0'
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param v [String AssUpdater::AssVersion] if not given return
|
32
|
+
# {.zerro_version}
|
33
|
+
def initialize(v = nil)
|
34
|
+
v ||= '0.0.0.0'
|
35
|
+
unless v.to_s =~ /^(\d)+\.(\d+)\.(\d+)\.(\d+)$/
|
36
|
+
fail ArgumentError,
|
37
|
+
"Invalid version string `#{v}'. Expect 'd.d.d.d' format"
|
38
|
+
end
|
39
|
+
@_1 = Regexp.last_match(1).to_i
|
40
|
+
@_2 = Regexp.last_match(2).to_i
|
41
|
+
@_3 = Regexp.last_match(3).to_i
|
42
|
+
@_4 = Regexp.last_match(4).to_i
|
43
|
+
end
|
44
|
+
|
45
|
+
# Conver version to array of digit group
|
46
|
+
# @return [Array<Fixnum>]
|
47
|
+
def to_a
|
48
|
+
[@_1, @_2, @_3, @_4]
|
49
|
+
end
|
50
|
+
|
51
|
+
# Convert version to string
|
52
|
+
# @return [Stgring]
|
53
|
+
def to_s
|
54
|
+
to_a.join('.')
|
55
|
+
end
|
56
|
+
|
57
|
+
# Return redaction number
|
58
|
+
# @return [String]
|
59
|
+
def redaction
|
60
|
+
to_a.shift(2).join('.')
|
61
|
+
end
|
62
|
+
|
63
|
+
# Compare versions
|
64
|
+
# @return [Boollean]
|
65
|
+
def <=>(other)
|
66
|
+
merge(other).each do |v|
|
67
|
+
if v[0] > v[1]
|
68
|
+
return 1
|
69
|
+
elsif v[0] < v[1]
|
70
|
+
return -1
|
71
|
+
end
|
72
|
+
end
|
73
|
+
0
|
74
|
+
end
|
75
|
+
|
76
|
+
# (see #<=>)
|
77
|
+
def ==(other)
|
78
|
+
(self <=> other) == 0
|
79
|
+
end
|
80
|
+
|
81
|
+
# (see #<=>)
|
82
|
+
def >(other)
|
83
|
+
(self <=> other) == 1
|
84
|
+
end
|
85
|
+
|
86
|
+
# (see #<=>)
|
87
|
+
def <(other)
|
88
|
+
(self <=> other) == -1
|
89
|
+
end
|
90
|
+
|
91
|
+
# (see #<=>)
|
92
|
+
def >=(other)
|
93
|
+
(self <=> other) >= 0
|
94
|
+
end
|
95
|
+
|
96
|
+
# (see #<=>)
|
97
|
+
def <=(other)
|
98
|
+
(self <=> other) <= 0
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def merge(o)
|
104
|
+
to_a.zip o.to_a
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
class AssUpdater
|
4
|
+
# HTTP access to 1C services.
|
5
|
+
# @note 1C servise often unavaileble and {#get} fail on timeout
|
6
|
+
class HTTP
|
7
|
+
# Value of useragent controled 1C web server and server may return 403 error
|
8
|
+
USER_AGENT_DEFAULT = '1C+Enterprise/8.2'
|
9
|
+
# (see USER_AGENT_DEFAULT)
|
10
|
+
# @return [String]
|
11
|
+
attr_accessor :user_agent
|
12
|
+
# see {#initialize} param
|
13
|
+
# @return [Hash]
|
14
|
+
attr_accessor :proxy_options
|
15
|
+
# see Net::HTTP#open_timeout
|
16
|
+
# @note (see AssUpdater::HTTP)
|
17
|
+
attr_accessor :open_timeout
|
18
|
+
# see Net::HTTP#read_timeout
|
19
|
+
# @note (see AssUpdater::HTTP)
|
20
|
+
attr_accessor :read_timeout
|
21
|
+
|
22
|
+
# @param proxy_options [Hash] options for proxy server
|
23
|
+
def initialize(proxy_options = {})
|
24
|
+
self.open_timeout = 30 # fucking 1C
|
25
|
+
self.user_agent = USER_AGENT_DEFAULT
|
26
|
+
self.proxy_options = { addr: nil,
|
27
|
+
port: nil,
|
28
|
+
user: nil,
|
29
|
+
pass: nil }.merge(proxy_options)
|
30
|
+
yeld self if block_given?
|
31
|
+
end
|
32
|
+
|
33
|
+
# @note (see AssUpdater::HTTP)
|
34
|
+
# @param uri_str [String]
|
35
|
+
# @param user_name [String] user 1C sevice
|
36
|
+
# @param password [String]
|
37
|
+
def get(uri_str, user_name = nil, password = nil)
|
38
|
+
response = _http(URI(uri_str)).request(_get(user_name,
|
39
|
+
password,
|
40
|
+
URI(uri_str)
|
41
|
+
)
|
42
|
+
)
|
43
|
+
_body(response, uri_str)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def _body(response, uri_str)
|
49
|
+
if response.code != '200'
|
50
|
+
fail AssUpdater::Error,
|
51
|
+
"#{response.code} #{response.message} for `#{uri_str}'"
|
52
|
+
end
|
53
|
+
response.body
|
54
|
+
end
|
55
|
+
|
56
|
+
def _http(uri)
|
57
|
+
h = Net::HTTP.new(uri.host,
|
58
|
+
uri.port,
|
59
|
+
proxy_options[:addr],
|
60
|
+
proxy_options[:port],
|
61
|
+
proxy_options[:user],
|
62
|
+
proxy_options[:pass]
|
63
|
+
)
|
64
|
+
timeouts h
|
65
|
+
end
|
66
|
+
|
67
|
+
def timeouts(h)
|
68
|
+
h.open_timeout = open_timeout
|
69
|
+
h.read_timeout = read_timeout
|
70
|
+
h
|
71
|
+
end
|
72
|
+
|
73
|
+
def _get(user, pass, uri)
|
74
|
+
g = Net::HTTP::Get.new(uri.path, 'User-Agent' => user_agent)
|
75
|
+
g.basic_auth user, pass if user
|
76
|
+
g
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
#-- encoding utf-8
|
2
|
+
|
3
|
+
class AssUpdater
|
4
|
+
# Implement work with distributives of configuration update
|
5
|
+
class UpdateDistrib
|
6
|
+
attr_reader :ass_updater, :version_info, :version, :target, :tmplt_root
|
7
|
+
|
8
|
+
# @param ass_updater [AssUpdater] owner object
|
9
|
+
# @param version [String AssUpdater::AssVersion]
|
10
|
+
# @param tmplt_root [String] path to 1C update templates
|
11
|
+
def initialize(version, tmplt_root, ass_updater)
|
12
|
+
@ass_updater = ass_updater
|
13
|
+
@version = AssUpdater::AssVersion.new(version)
|
14
|
+
@version_info = @ass_updater.update_history[@version]
|
15
|
+
@tmplt_root = tmplt_root
|
16
|
+
@target = AssUpdater::AssVersion.convert_array version_info['target']
|
17
|
+
end
|
18
|
+
|
19
|
+
# Download <version> distributive of configuration update and uzip into
|
20
|
+
# tmplt_root. Exists in template_root distrib will be overwritten.
|
21
|
+
# @note Require authorization.
|
22
|
+
# @note Service http://downloads.v8.1c.ru
|
23
|
+
# often unavailable and it fail on timeout. Don't worry and try again.
|
24
|
+
# @param user [String] authorization user name
|
25
|
+
# @param password [String] authorization password
|
26
|
+
# @return [AssUpdater::UpdateDistrib] self
|
27
|
+
def get(user, password)
|
28
|
+
zip_f = Tempfile.new('1cv8_zip')
|
29
|
+
begin
|
30
|
+
download_distrib(zip_f, user, password)
|
31
|
+
zip_f.rewind
|
32
|
+
unzip_all(zip_f)
|
33
|
+
ensure
|
34
|
+
zip_f.close
|
35
|
+
zip_f.unlink
|
36
|
+
end
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
# Return path to distributive zip file on http server
|
41
|
+
def file
|
42
|
+
File.join(AssUpdater::UPDATEREPO_BASE, fix_path(version_info_file))
|
43
|
+
end
|
44
|
+
|
45
|
+
# Return local path where distributive installed
|
46
|
+
def local_path
|
47
|
+
File.join(tmplt_root, File.dirname(version_info_file))
|
48
|
+
end
|
49
|
+
|
50
|
+
# Return files included in distributive. Files find in {#local_path}
|
51
|
+
# @param pattern (see Dir::glob)
|
52
|
+
def file_list(pattern = '*')
|
53
|
+
Dir.glob(File.join(local_path, pattern)).map do |f|
|
54
|
+
f.force_encoding 'UTF-8'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def version_info_file
|
61
|
+
fix_path version_info['file']
|
62
|
+
end
|
63
|
+
|
64
|
+
def fix_path(path)
|
65
|
+
path.tr '\\', '/'
|
66
|
+
end
|
67
|
+
|
68
|
+
def unzip_all(zip_f)
|
69
|
+
dest_dir = ''
|
70
|
+
Zip::File.open(zip_f.path) do |zf|
|
71
|
+
dest_dir = FileUtils.mkdir_p(local_path)[0]
|
72
|
+
zf.each do |entry|
|
73
|
+
dest_file = File.join(dest_dir, entry.name.encode('UTF-8', 'cp866'))
|
74
|
+
FileUtils.rm_r(dest_file) if File.exist?(dest_file)
|
75
|
+
entry.extract(dest_file)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
dest_dir
|
79
|
+
end
|
80
|
+
|
81
|
+
def download_distrib(tmp_f, user, password)
|
82
|
+
tmp_f.write(ass_updater.http.get(file,
|
83
|
+
user,
|
84
|
+
password
|
85
|
+
)
|
86
|
+
)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
#-- incoding utf-8
|
2
|
+
|
3
|
+
class AssUpdater
|
4
|
+
#
|
5
|
+
# Handle fo updtade history from v8upd11.xml
|
6
|
+
# @note (see AssUpdater::UpdateInfoService)
|
7
|
+
#
|
8
|
+
class UpdateHistory < AssUpdater::UpdateInfoService
|
9
|
+
# Returm min distrib version from update history
|
10
|
+
# @return [AssUpdater::AssVersion]
|
11
|
+
def min_version
|
12
|
+
all_versions.min
|
13
|
+
end
|
14
|
+
|
15
|
+
# Return max version from update histry
|
16
|
+
# @return [AssUpdater::AssVersion]
|
17
|
+
def max_version
|
18
|
+
all_versions.max
|
19
|
+
end
|
20
|
+
|
21
|
+
# Return all versions found in histry
|
22
|
+
# @return [Array<AssUpdater::AssVersion>]
|
23
|
+
def all_versions
|
24
|
+
r = []
|
25
|
+
raw['update'].each do |h|
|
26
|
+
r << h['version']
|
27
|
+
end
|
28
|
+
AssUpdater::AssVersion.convert_array r
|
29
|
+
end
|
30
|
+
|
31
|
+
# Return info about version <version>
|
32
|
+
# @param version [String,AssUpdater::AssVersion]
|
33
|
+
# @return [Hash]
|
34
|
+
# @raise [AssUpdater::Error] if info for version not found
|
35
|
+
def [](version)
|
36
|
+
return [min_version] if version.to_s == '0.0.0.0'
|
37
|
+
raw['update'].each do |h|
|
38
|
+
next if h['version'] != version.to_s
|
39
|
+
h['target'] = [] << h['target'] if h['target'].is_a? String
|
40
|
+
return h
|
41
|
+
end
|
42
|
+
fail AssUpdater::Error, "Unkown version number `#{version}'"
|
43
|
+
end
|
44
|
+
|
45
|
+
# Return array of target versions for update to version <version>
|
46
|
+
# @param version [String,AssUpdater::AssVersion]
|
47
|
+
# @return [Array<AssUpdater::AssVersion>]
|
48
|
+
# @note (see #ex
|
49
|
+
def target(version)
|
50
|
+
exclude_unknown_version(
|
51
|
+
AssUpdater::AssVersion.convert_array self[version]['target']
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# @note Often ['target'] containe incorrect version number
|
58
|
+
# not fonded in {#all_versions}.
|
59
|
+
#
|
60
|
+
def exclude_unknown_version(a)
|
61
|
+
a.map do |i|
|
62
|
+
i if all_versions.index(i)
|
63
|
+
end.compact
|
64
|
+
end
|
65
|
+
|
66
|
+
def parse
|
67
|
+
r = Nori.new(parser: :rexml,
|
68
|
+
strip_namespaces: true).parse(get)['updateList']
|
69
|
+
r['update'] = [] << r['update'] if r['update'].is_a? Hash
|
70
|
+
r
|
71
|
+
end
|
72
|
+
|
73
|
+
def get
|
74
|
+
zip_f = Tempfile.new('upd11_zip')
|
75
|
+
begin
|
76
|
+
zip_f.write(ass_updater.http.get("#{updateinfo_path}/#{UPD11_ZIP}"))
|
77
|
+
zip_f.rewind
|
78
|
+
xml = unzip(zip_f)
|
79
|
+
ensure
|
80
|
+
zip_f.close
|
81
|
+
zip_f.unlink
|
82
|
+
end
|
83
|
+
xml.force_encoding 'UTF-8'
|
84
|
+
end
|
85
|
+
|
86
|
+
def unzip(zip_f)
|
87
|
+
xml = ''
|
88
|
+
Zip::File.open(zip_f.path) do |zf|
|
89
|
+
upd11_zip = zf.glob('v8cscdsc.xml').first
|
90
|
+
unless upd11_zip
|
91
|
+
fail AssUpdater::Error,
|
92
|
+
"File `v8cscdsc.xml' not fount in zip `#{UPD11_ZIP}'"
|
93
|
+
end
|
94
|
+
xml = upd11_zip.get_input_stream.read
|
95
|
+
end
|
96
|
+
xml
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#-- encoding utf-8
|
2
|
+
|
3
|
+
class AssUpdater
|
4
|
+
#
|
5
|
+
# Handle for UpdInfo.txt
|
6
|
+
#
|
7
|
+
class UpdateInfo < AssUpdater::UpdateInfoService
|
8
|
+
UPDINFO_TXT = 'UpdInfo.txt'
|
9
|
+
|
10
|
+
# Return last configuration release version from file UpdInfo.txt.
|
11
|
+
# @return [AssUpdater::AssVersion]
|
12
|
+
def version
|
13
|
+
AssUpdater::AssVersion.new(self[:version])
|
14
|
+
end
|
15
|
+
|
16
|
+
# Return value for key from UpdInfo.txt
|
17
|
+
# @param key [Symbol] :version, :from_versions, :update_date
|
18
|
+
def [](key)
|
19
|
+
raw[key]
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def parse
|
25
|
+
get =~ /Version=([\d\.]*)(\s*)FromVersions=\
|
26
|
+
[;]?([\d\.\;]*)(\s*)UpdateDate=([\d\.]*)/im
|
27
|
+
r = { version: Regexp.last_match(1),
|
28
|
+
from_versions: [],
|
29
|
+
update_date: Regexp.last_match(5)
|
30
|
+
}
|
31
|
+
r[:from_versions] = Regexp.last_match(3).split(';') if Regexp.last_match 3
|
32
|
+
r
|
33
|
+
end
|
34
|
+
|
35
|
+
def get
|
36
|
+
ass_updater.http.get("#{updateinfo_path}/#{UPDINFO_TXT}")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#-- encoding utf-8
|
2
|
+
|
3
|
+
class AssUpdater
|
4
|
+
# @abstract
|
5
|
+
# @note Service http://downloads.1c.ru often unavailable and initialize fail
|
6
|
+
# on timeout. Don't worry and try again.
|
7
|
+
class UpdateInfoService
|
8
|
+
attr_reader :ass_updater
|
9
|
+
|
10
|
+
# @param ass_updater [AssUpdater] owner objec
|
11
|
+
def initialize(ass_updater)
|
12
|
+
@ass_updater = ass_updater
|
13
|
+
raw
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Return raw data
|
19
|
+
# @return [Hash]
|
20
|
+
def raw
|
21
|
+
@raw ||= parse
|
22
|
+
end
|
23
|
+
|
24
|
+
def updateinfo_base
|
25
|
+
AssUpdater::UPDATEINFO_BASE
|
26
|
+
end
|
27
|
+
|
28
|
+
def updateinfo_path
|
29
|
+
"#{updateinfo_base}/#{ass_updater.conf_code_name}/"\
|
30
|
+
"#{ass_updater.conf_redaction.sub('.', '')}/"\
|
31
|
+
"#{ass_updater.platform_version.sub('.', '')}/"
|
32
|
+
end
|
33
|
+
|
34
|
+
def parse
|
35
|
+
fail 'Abstract method called'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ass_updater
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Leonid Vlasov
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-10-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rubyzip
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: nori
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.10'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.10'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: minitest
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: simplecov
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: Wrapper for 1C configuration updates service
|
112
|
+
email:
|
113
|
+
- leoniv.vlasov@gmail.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- .gitignore
|
119
|
+
- .rubocop.yml
|
120
|
+
- .travis.yml
|
121
|
+
- Gemfile
|
122
|
+
- README.md
|
123
|
+
- Rakefile
|
124
|
+
- ass_updater.gemspec
|
125
|
+
- bin/console
|
126
|
+
- bin/setup
|
127
|
+
- lib/ass_updater.rb
|
128
|
+
- lib/ass_updater/ass_version.rb
|
129
|
+
- lib/ass_updater/http.rb
|
130
|
+
- lib/ass_updater/update_distrib.rb
|
131
|
+
- lib/ass_updater/update_history.rb
|
132
|
+
- lib/ass_updater/update_info.rb
|
133
|
+
- lib/ass_updater/update_info_service.rb
|
134
|
+
- lib/ass_updater/version.rb
|
135
|
+
homepage: https://github.com/leoniv/ass_updater
|
136
|
+
licenses:
|
137
|
+
- MIT
|
138
|
+
metadata: {}
|
139
|
+
post_install_message:
|
140
|
+
rdoc_options: []
|
141
|
+
require_paths:
|
142
|
+
- lib
|
143
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - '>='
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0'
|
148
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - '>='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
requirements: []
|
154
|
+
rubyforge_project:
|
155
|
+
rubygems_version: 2.0.14
|
156
|
+
signing_key:
|
157
|
+
specification_version: 4
|
158
|
+
summary: Wrapper for 1C configuration updates service
|
159
|
+
test_files: []
|