oats 0.0.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.
- data/.gitignore +6 -0
- data/Gemfile +15 -0
- data/README.txt +165 -0
- data/Rakefile +2 -0
- data/bin/agent +204 -0
- data/bin/oats +10 -0
- data/bin/occ +29 -0
- data/bin/results_cleanup +6 -0
- data/doc/COPYING +55 -0
- data/doc/LICENSE +55 -0
- data/doc/OATS_Framework.doc +0 -0
- data/doc/classes/ApplicationLogs.html +239 -0
- data/doc/classes/Campaign.html +843 -0
- data/doc/classes/CommandlineOptions.html +131 -0
- data/doc/classes/Driver.html +182 -0
- data/doc/classes/Hash.html +137 -0
- data/doc/classes/Ide.html +194 -0
- data/doc/classes/MapSelenium.html +197 -0
- data/doc/classes/Net.html +107 -0
- data/doc/classes/Oats/OatsFilterError.html +119 -0
- data/doc/classes/Oats.html +998 -0
- data/doc/classes/OatsAssertError.html +119 -0
- data/doc/classes/OatsBadInput.html +119 -0
- data/doc/classes/OatsData.html +290 -0
- data/doc/classes/OatsError.html +117 -0
- data/doc/classes/OatsExit.html +117 -0
- data/doc/classes/OatsLock.html +254 -0
- data/doc/classes/OatsMain.html +182 -0
- data/doc/classes/OatsMysqlError.html +113 -0
- data/doc/classes/OatsMysqlMissingInput.html +113 -0
- data/doc/classes/OatsReportError.html +113 -0
- data/doc/classes/OatsSetupError.html +119 -0
- data/doc/classes/OatsTestError.html +119 -0
- data/doc/classes/OatsTestExit.html +119 -0
- data/doc/classes/OatsTestLocateError.html +120 -0
- data/doc/classes/OatsVerifyError.html +119 -0
- data/doc/classes/Ragent.html +397 -0
- data/doc/classes/Rclient.html +236 -0
- data/doc/classes/Report.html +368 -0
- data/doc/classes/Reports.html +244 -0
- data/doc/classes/RestApi.html +333 -0
- data/doc/classes/RhttpClient.html +236 -0
- data/doc/classes/Rimap.html +170 -0
- data/doc/classes/Rmysql.html +176 -0
- data/doc/classes/Roptions.html +131 -0
- data/doc/classes/Rselenium.html +233 -0
- data/doc/classes/Rssh.html +138 -0
- data/doc/classes/Runnable.html +174 -0
- data/doc/classes/SFTriggers.html +206 -0
- data/doc/classes/Selenium/Client/Driver.html +211 -0
- data/doc/classes/Selenium/Client.html +107 -0
- data/doc/classes/Selenium.html +107 -0
- data/doc/classes/SystemCapture.html +304 -0
- data/doc/classes/TestCase.html +418 -0
- data/doc/classes/TestData.html +235 -0
- data/doc/classes/TestList.html +264 -0
- data/doc/classes/Tools.html +244 -0
- data/doc/classes/Util.html +201 -0
- data/doc/classes/Variation.html +206 -0
- data/doc/fr_class_index.html +92 -0
- data/doc/fr_method_index.html +465 -0
- data/doc/index.html +23 -0
- data/doc/oats_httpd.conf +32 -0
- data/doc/oats_user.yml +25 -0
- data/doc/rdoc-style.css +208 -0
- data/lib/deep_merge/.gitignore +2 -0
- data/lib/deep_merge/core.rb +195 -0
- data/lib/deep_merge/deep_merge.rb +1 -0
- data/lib/deep_merge/deep_merge_hash.rb +28 -0
- data/lib/deep_merge/rails_compat.rb +27 -0
- data/lib/oats/application_logs.rb +163 -0
- data/lib/oats/build_id.rb +58 -0
- data/lib/oats/commandline_options.rb +128 -0
- data/lib/oats/diff.rb +278 -0
- data/lib/oats/driver.rb +492 -0
- data/lib/oats/ide.rb +227 -0
- data/lib/oats/keywords.rb +67 -0
- data/lib/oats/log4r_init.rb +14 -0
- data/lib/oats/mysql.rb +97 -0
- data/lib/oats/oats.rb +637 -0
- data/lib/oats/oats_data.rb +400 -0
- data/lib/oats/oats_exceptions.rb +25 -0
- data/lib/oats/oats_lock.rb +261 -0
- data/lib/oats/oats_selenium_api.rb +639 -0
- data/lib/oats/oselenium.rb +189 -0
- data/lib/oats/ossh.rb +36 -0
- data/lib/oats/patches_for_eventmachine_12.10.rb +66 -0
- data/lib/oats/ragent.rb +321 -0
- data/lib/oats/rclient.rb +42 -0
- data/lib/oats/report.rb +207 -0
- data/lib/oats/roptions.rb +88 -0
- data/lib/oats/test_case.rb +510 -0
- data/lib/oats/test_data.rb +98 -0
- data/lib/oats/test_list.rb +141 -0
- data/lib/oats/unixdiff.rb +75 -0
- data/lib/oats/util.rb +125 -0
- data/lib/oats/version.rb +3 -0
- data/lib/oats.rb +36 -0
- data/nbproject/configs/agent.properties +0 -0
- data/nbproject/configs/gr.properties +0 -0
- data/nbproject/project.properties +10 -0
- data/nbproject/project.xml +17 -0
- data/oats.gemspec +42 -0
- data/oats_ini.yml +258 -0
- data/oats_tests/Gemfile +18 -0
- data/oats_tests/aut_ini.yml +30 -0
- data/oats_tests/bin/oats +8 -0
- data/oats_tests/environments/qa.yml +4 -0
- data/oats_tests/environments/qa_chrome.yml +4 -0
- data/oats_tests/examples/core/coreExamples.yml +8 -0
- data/oats_tests/examples/core/expectedException.rb +39 -0
- data/oats_tests/examples/core/ok_verify.rb +2 -0
- data/oats_tests/examples/core/ok_verify.rb_ok/out/myfile.txt +1 -0
- data/oats_tests/examples/core/ok_verify.rb_ok/out/myfile2.txt +1 -0
- data/oats_tests/examples/core/ok_verify.rb_ok/rats_test.log +2 -0
- data/oats_tests/examples/core/unexpectedException.rb +30 -0
- data/oats_tests/examples/examples.yml +13 -0
- data/oats_tests/examples/gui/guiExamples.yml +7 -0
- data/oats_tests/examples/gui/seleniumGoogle.rb +10 -0
- data/oats_tests/examples/gui/webdriverGoogle.rb +9 -0
- data/oats_tests/examples/keywords/SampleXlList-1.xls +0 -0
- data/oats_tests/examples/keywords/SampleXlList-2.xls +0 -0
- data/oats_tests/examples/keywords/SampleXlLists.xls +0 -0
- data/oats_tests/examples/keywords/keywordsDriver.rb +1 -0
- data/oats_tests/examples/keywords/keywordsExamples.yml +8 -0
- data/oats_tests/examples/keywords/keywordsTC1.yml +5 -0
- data/oats_tests/examples/keywords/keywordsTestlist.yml +16 -0
- data/oats_tests/examples/needsWork/addTestDynamically.rb +4 -0
- data/oats_tests/examples/needsWork/emailVerify.rb +34 -0
- data/oats_tests/examples/needsWork/testSql/rtest.sql +6 -0
- data/oats_tests/examples/needsWork/testSql/rtest.yml +11 -0
- data/oats_tests/examples/occTest/occTest.rb +13 -0
- data/oats_tests/examples/occTest/occTest_1.rb +1 -0
- data/oats_tests/examples/occTest/occTest_1_1.rb +1 -0
- data/oats_tests/examples/occTest/occTest_1_2.rb +1 -0
- data/oats_tests/examples/occTest/occTest_1_3.rb +1 -0
- data/oats_tests/examples/occTest/occTest_1_4.rb +1 -0
- data/oats_tests/examples/occTest/occTest_2.rb +1 -0
- data/oats_tests/examples/occTest/occTest_2_1.rb +1 -0
- data/oats_tests/examples/occTest/occTest_2_2.rb +1 -0
- data/oats_tests/examples/occTest/occTest_2_3.rb +1 -0
- data/oats_tests/examples/occTest/occTest_2_4.rb +1 -0
- data/oats_tests/examples/occTest/occTest_3.rb +1 -0
- data/oats_tests/examples/occTest/occTest_3_1.rb +1 -0
- data/oats_tests/examples/occTest/occTest_3_2.rb +1 -0
- data/oats_tests/examples/occTest/occTest_3_3.rb +1 -0
- data/oats_tests/examples/occTest/occTest_3_4.rb +1 -0
- data/oats_tests/examples/occTest/occTest_4.rb +1 -0
- data/oats_tests/examples/occTest/occTestlist.yml +9 -0
- data/oats_tests/examples/occTest/occTestlist_1.yml +9 -0
- data/oats_tests/examples/occTest/occTestlist_2.yml +9 -0
- data/oats_tests/examples/occTest/occTestlist_3.yml +9 -0
- data/oats_tests/examples/occTest/variation1.yml +4 -0
- data/oats_tests/examples/occTest/variation2.yml +4 -0
- data/oats_tests/examples/testFileLocationUnitTests/extn_driver.rb +4 -0
- data/oats_tests/examples/testFileLocationUnitTests/folder/oats.yml +3 -0
- data/oats_tests/examples/testFileLocationUnitTests/folder/t1.rb +2 -0
- data/oats_tests/examples/testFileLocationUnitTests/folder1/t1.yml +2 -0
- data/oats_tests/examples/testFileLocationUnitTests/folder1/t1_1.yml +3 -0
- data/oats_tests/examples/testFileLocationUnitTests/folder2/oats.yml +3 -0
- data/oats_tests/examples/testFileLocationUnitTests/folder2/t1.rb +2 -0
- data/oats_tests/examples/testFileLocationUnitTests/folder2/t1.yml +2 -0
- data/oats_tests/examples/testFileLocationUnitTests/no_yaml.rb +3 -0
- data/oats_tests/examples/testFileLocationUnitTests/post_yaml.rb +1 -0
- data/oats_tests/examples/testFileLocationUnitTests/t1.rb +4 -0
- data/oats_tests/examples/testFileLocationUnitTests/t1.yml +2 -0
- data/oats_tests/examples/testFileLocationUnitTests/t1_1.yml +3 -0
- data/oats_tests/examples/testFileLocationUnitTests/testDir/oats.yml +3 -0
- data/oats_tests/examples/testFileLocationUnitTests/testDir/t1.rb +2 -0
- data/oats_tests/examples/testFileLocationUnitTests/testDir/t1.yml +2 -0
- data/oats_tests/examples/testFileLocationUnitTests/testDir2/t1.rb +2 -0
- data/oats_tests/examples/testFileLocationUnitTests/testDir2/t1.yml +2 -0
- data/oats_tests/examples/testFileLocationUnitTests/unitTestList.yml +36 -0
- data/oats_tests/examples/testFileLocationUnitTests/yml_driver.rb +2 -0
- data/oats_tests/lib/business.rb +28 -0
- data/oats_tests/lib/sample_xl_lists.rb +37 -0
- data/test/common_test_unit_setup.rb +21 -0
- data/test/test_basic.rb +16 -0
- data/test/test_selenium.rb +16 -0
- data/test/test_xl_lists.rb +16 -0
- metadata +291 -0
data/doc/rdoc-style.css
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
|
|
2
|
+
body {
|
|
3
|
+
font-family: Verdana,Arial,Helvetica,sans-serif;
|
|
4
|
+
font-size: 90%;
|
|
5
|
+
margin: 0;
|
|
6
|
+
margin-left: 40px;
|
|
7
|
+
padding: 0;
|
|
8
|
+
background: white;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
|
|
12
|
+
h1 { font-size: 150%; }
|
|
13
|
+
h2,h3,h4 { margin-top: 1em; }
|
|
14
|
+
|
|
15
|
+
a { background: #eef; color: #039; text-decoration: none; }
|
|
16
|
+
a:hover { background: #039; color: #eef; }
|
|
17
|
+
|
|
18
|
+
/* Override the base stylesheet's Anchor inside a table cell */
|
|
19
|
+
td > a {
|
|
20
|
+
background: transparent;
|
|
21
|
+
color: #039;
|
|
22
|
+
text-decoration: none;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* and inside a section title */
|
|
26
|
+
.section-title > a {
|
|
27
|
+
background: transparent;
|
|
28
|
+
color: #eee;
|
|
29
|
+
text-decoration: none;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* === Structural elements =================================== */
|
|
33
|
+
|
|
34
|
+
div#index {
|
|
35
|
+
margin: 0;
|
|
36
|
+
margin-left: -40px;
|
|
37
|
+
padding: 0;
|
|
38
|
+
font-size: 90%;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
div#index a {
|
|
43
|
+
margin-left: 0.7em;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
div#index .section-bar {
|
|
47
|
+
margin-left: 0px;
|
|
48
|
+
padding-left: 0.7em;
|
|
49
|
+
background: #ccc;
|
|
50
|
+
font-size: small;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
div#classHeader, div#fileHeader {
|
|
55
|
+
width: auto;
|
|
56
|
+
color: white;
|
|
57
|
+
padding: 0.5em 1.5em 0.5em 1.5em;
|
|
58
|
+
margin: 0;
|
|
59
|
+
margin-left: -40px;
|
|
60
|
+
border-bottom: 3px solid #006;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
div#classHeader a, div#fileHeader a {
|
|
64
|
+
background: inherit;
|
|
65
|
+
color: white;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
div#classHeader td, div#fileHeader td {
|
|
69
|
+
background: inherit;
|
|
70
|
+
color: white;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
div#fileHeader {
|
|
75
|
+
background: #057;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
div#classHeader {
|
|
79
|
+
background: #048;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
.class-name-in-header {
|
|
84
|
+
font-size: 180%;
|
|
85
|
+
font-weight: bold;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
div#bodyContent {
|
|
90
|
+
padding: 0 1.5em 0 1.5em;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
div#description {
|
|
94
|
+
padding: 0.5em 1.5em;
|
|
95
|
+
background: #efefef;
|
|
96
|
+
border: 1px dotted #999;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
div#description h1,h2,h3,h4,h5,h6 {
|
|
100
|
+
color: #125;;
|
|
101
|
+
background: transparent;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
div#validator-badges {
|
|
105
|
+
text-align: center;
|
|
106
|
+
}
|
|
107
|
+
div#validator-badges img { border: 0; }
|
|
108
|
+
|
|
109
|
+
div#copyright {
|
|
110
|
+
color: #333;
|
|
111
|
+
background: #efefef;
|
|
112
|
+
font: 0.75em sans-serif;
|
|
113
|
+
margin-top: 5em;
|
|
114
|
+
margin-bottom: 0;
|
|
115
|
+
padding: 0.5em 2em;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
/* === Classes =================================== */
|
|
120
|
+
|
|
121
|
+
table.header-table {
|
|
122
|
+
color: white;
|
|
123
|
+
font-size: small;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.type-note {
|
|
127
|
+
font-size: small;
|
|
128
|
+
color: #DEDEDE;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.xxsection-bar {
|
|
132
|
+
background: #eee;
|
|
133
|
+
color: #333;
|
|
134
|
+
padding: 3px;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.section-bar {
|
|
138
|
+
color: #333;
|
|
139
|
+
border-bottom: 1px solid #999;
|
|
140
|
+
margin-left: -20px;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
.section-title {
|
|
145
|
+
background: #79a;
|
|
146
|
+
color: #eee;
|
|
147
|
+
padding: 3px;
|
|
148
|
+
margin-top: 2em;
|
|
149
|
+
margin-left: -30px;
|
|
150
|
+
border: 1px solid #999;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.top-aligned-row { vertical-align: top }
|
|
154
|
+
.bottom-aligned-row { vertical-align: bottom }
|
|
155
|
+
|
|
156
|
+
/* --- Context section classes ----------------------- */
|
|
157
|
+
|
|
158
|
+
.context-row { }
|
|
159
|
+
.context-item-name { font-family: monospace; font-weight: bold; color: black; }
|
|
160
|
+
.context-item-value { font-size: small; color: #448; }
|
|
161
|
+
.context-item-desc { color: #333; padding-left: 2em; }
|
|
162
|
+
|
|
163
|
+
/* --- Method classes -------------------------- */
|
|
164
|
+
.method-detail {
|
|
165
|
+
background: #efefef;
|
|
166
|
+
padding: 0;
|
|
167
|
+
margin-top: 0.5em;
|
|
168
|
+
margin-bottom: 1em;
|
|
169
|
+
border: 1px dotted #ccc;
|
|
170
|
+
}
|
|
171
|
+
.method-heading {
|
|
172
|
+
color: black;
|
|
173
|
+
background: #ccc;
|
|
174
|
+
border-bottom: 1px solid #666;
|
|
175
|
+
padding: 0.2em 0.5em 0 0.5em;
|
|
176
|
+
}
|
|
177
|
+
.method-signature { color: black; background: inherit; }
|
|
178
|
+
.method-name { font-weight: bold; }
|
|
179
|
+
.method-args { font-style: italic; }
|
|
180
|
+
.method-description { padding: 0 0.5em 0 0.5em; }
|
|
181
|
+
|
|
182
|
+
/* --- Source code sections -------------------- */
|
|
183
|
+
|
|
184
|
+
a.source-toggle { font-size: 90%; }
|
|
185
|
+
div.method-source-code {
|
|
186
|
+
background: #262626;
|
|
187
|
+
color: #ffdead;
|
|
188
|
+
margin: 1em;
|
|
189
|
+
padding: 0.5em;
|
|
190
|
+
border: 1px dashed #999;
|
|
191
|
+
overflow: hidden;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
div.method-source-code pre { color: #ffdead; overflow: hidden; }
|
|
195
|
+
|
|
196
|
+
/* --- Ruby keyword styles --------------------- */
|
|
197
|
+
|
|
198
|
+
.standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
|
|
199
|
+
|
|
200
|
+
.ruby-constant { color: #7fffd4; background: transparent; }
|
|
201
|
+
.ruby-keyword { color: #00ffff; background: transparent; }
|
|
202
|
+
.ruby-ivar { color: #eedd82; background: transparent; }
|
|
203
|
+
.ruby-operator { color: #00ffee; background: transparent; }
|
|
204
|
+
.ruby-identifier { color: #ffdead; background: transparent; }
|
|
205
|
+
.ruby-node { color: #ffa07a; background: transparent; }
|
|
206
|
+
.ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
|
|
207
|
+
.ruby-regexp { color: #ffa07a; background: transparent; }
|
|
208
|
+
.ruby-value { color: #7fffd4; background: transparent; }
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
module DeepMerge
|
|
2
|
+
|
|
3
|
+
class InvalidParameter < StandardError; end
|
|
4
|
+
|
|
5
|
+
# DEFAULT_FIELD_KNOCKOUT_PREFIX = '--'
|
|
6
|
+
|
|
7
|
+
# Deep Merge core documentation.
|
|
8
|
+
# deep_merge! method permits merging of arbitrary child elements. The two top level
|
|
9
|
+
# elements must be hashes. These hashes can contain unlimited (to stack limit) levels
|
|
10
|
+
# of child elements. These child elements to not have to be of the same types.
|
|
11
|
+
# Where child elements are of the same type, deep_merge will attempt to merge them together.
|
|
12
|
+
# Where child elements are not of the same type, deep_merge will skip or optionally overwrite
|
|
13
|
+
# the destination element with the contents of the source element at that level.
|
|
14
|
+
# So if you have two hashes like this:
|
|
15
|
+
# source = {:x => [1,2,3], :y => 2}
|
|
16
|
+
# dest = {:x => [4,5,'6'], :y => [7,8,9]}
|
|
17
|
+
# dest.deep_merge!(source)
|
|
18
|
+
# Results: {:x => [1,2,3,4,5,'6'], :y => 2}
|
|
19
|
+
# By default, "deep_merge!" will overwrite any unmergeables and merge everything else.
|
|
20
|
+
# To avoid this, use "deep_merge" (no bang/exclamation mark)
|
|
21
|
+
#
|
|
22
|
+
# Options:
|
|
23
|
+
# Options are specified in the last parameter passed, which should be in hash format:
|
|
24
|
+
# hash.deep_merge!({:x => [1,2]}, {:knockout_prefix => '--'})
|
|
25
|
+
# :preserve_unmergeables DEFAULT: false
|
|
26
|
+
# Set to true to skip any unmergeable elements from source
|
|
27
|
+
# :overwrite_arrays DEFAULT: false
|
|
28
|
+
# Set to true to not merge but overwrite arrays
|
|
29
|
+
# :knockout_prefix DEFAULT: nil
|
|
30
|
+
# Set to string value to signify prefix which deletes elements from existing element
|
|
31
|
+
# :sort_merged_arrays DEFAULT: false
|
|
32
|
+
# Set to true to sort all arrays that are merged together
|
|
33
|
+
# :unpack_arrays DEFAULT: nil
|
|
34
|
+
# Set to string value to run "Array::join" then "String::split" against all arrays
|
|
35
|
+
# :merge_debug DEFAULT: false
|
|
36
|
+
# Set to true to get console output of merge process for debugging
|
|
37
|
+
#
|
|
38
|
+
# Selected Options Details:
|
|
39
|
+
# :knockout_prefix => The purpose of this is to provide a way to remove elements
|
|
40
|
+
# from existing Hash by specifying them in a special way in incoming hash
|
|
41
|
+
# source = {:x => ['--1', '2']}
|
|
42
|
+
# dest = {:x => ['1', '3']}
|
|
43
|
+
# dest.ko_deep_merge!(source)
|
|
44
|
+
# Results: {:x => ['2','3']}
|
|
45
|
+
# Additionally, if the knockout_prefix is passed alone as a string, it will cause
|
|
46
|
+
# the entire element to be removed:
|
|
47
|
+
# source = {:x => '--'}
|
|
48
|
+
# dest = {:x => [1,2,3]}
|
|
49
|
+
# dest.ko_deep_merge!(source)
|
|
50
|
+
# Results: {:x => ""}
|
|
51
|
+
# :unpack_arrays => The purpose of this is to permit compound elements to be passed
|
|
52
|
+
# in as strings and to be converted into discrete array elements
|
|
53
|
+
# irsource = {:x => ['1,2,3', '4']}
|
|
54
|
+
# dest = {:x => ['5','6','7,8']}
|
|
55
|
+
# dest.deep_merge!(source, {:unpack_arrays => ','})
|
|
56
|
+
# Results: {:x => ['1','2','3','4','5','6','7','8'}
|
|
57
|
+
# Why: If receiving data from an HTML form, this makes it easy for a checkbox
|
|
58
|
+
# to pass multiple values from within a single HTML element
|
|
59
|
+
#
|
|
60
|
+
# There are many tests for this library - and you can learn more about the features
|
|
61
|
+
# and usages of deep_merge! by just browsing the test examples
|
|
62
|
+
def self.deep_merge!(source, dest, options = {})
|
|
63
|
+
# turn on this line for stdout debugging text
|
|
64
|
+
merge_debug = options[:merge_debug] || false
|
|
65
|
+
overwrite_unmergeable = !options[:preserve_unmergeables]
|
|
66
|
+
knockout_prefix = options[:knockout_prefix] || nil
|
|
67
|
+
raise InvalidParameter, "knockout_prefix cannot be an empty string in deep_merge!" if knockout_prefix == ""
|
|
68
|
+
raise InvalidParameter, "overwrite_unmergeable must be true if knockout_prefix is specified in deep_merge!" if knockout_prefix && !overwrite_unmergeable
|
|
69
|
+
# if present: we will split and join arrays on this char before merging
|
|
70
|
+
array_split_char = options[:unpack_arrays] || false
|
|
71
|
+
# Don't merge but overwrite arrays
|
|
72
|
+
overwrite_arrays = options[:overwrite_arrays] || false
|
|
73
|
+
# request that we sort together any arrays when they are merged
|
|
74
|
+
sort_merged_arrays = options[:sort_merged_arrays] || false
|
|
75
|
+
di = options[:debug_indent] || ''
|
|
76
|
+
# do nothing if source is nil
|
|
77
|
+
return dest if source.nil? || (source.respond_to?(:blank?) && source.blank?)
|
|
78
|
+
# if dest doesn't exist, then simply copy source to it
|
|
79
|
+
if !(dest) && overwrite_unmergeable
|
|
80
|
+
dest = source; return dest
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
puts "#{di}Source class: #{source.class.inspect} :: Dest class: #{dest.class.inspect}" if merge_debug
|
|
84
|
+
if source.kind_of?(Hash)
|
|
85
|
+
puts "#{di}Hashes: #{source.inspect} :: #{dest.inspect}" if merge_debug
|
|
86
|
+
source.each do |src_key, src_value|
|
|
87
|
+
if dest.kind_of?(Hash)
|
|
88
|
+
puts "#{di} looping: #{src_key.inspect} => #{src_value.inspect} :: #{dest.inspect}" if merge_debug
|
|
89
|
+
if dest[src_key]
|
|
90
|
+
puts "#{di} ==>merging: #{src_key.inspect} => #{src_value.inspect} :: #{dest[src_key].inspect}" if merge_debug
|
|
91
|
+
dest[src_key] = deep_merge!(src_value, dest[src_key], options.merge(:debug_indent => di + ' '))
|
|
92
|
+
else # dest[src_key] doesn't exist so we want to create and overwrite it (but we do this via deep_merge!)
|
|
93
|
+
puts "#{di} ==>merging over: #{src_key.inspect} => #{src_value.inspect}" if merge_debug
|
|
94
|
+
# note: we rescue here b/c some classes respond to "dup" but don't implement it (Numeric, TrueClass, FalseClass, NilClass among maybe others)
|
|
95
|
+
begin
|
|
96
|
+
src_dup = src_value.dup # we dup src_value if possible because we're going to merge into it (since dest is empty)
|
|
97
|
+
rescue TypeError
|
|
98
|
+
src_dup = src_value
|
|
99
|
+
end
|
|
100
|
+
dest[src_key] = deep_merge!(src_value, src_dup, options.merge(:debug_indent => di + ' '))
|
|
101
|
+
end
|
|
102
|
+
else # dest isn't a hash, so we overwrite it completely (if permitted)
|
|
103
|
+
if overwrite_unmergeable
|
|
104
|
+
puts "#{di} overwriting dest: #{src_key.inspect} => #{src_value.inspect} -over-> #{dest.inspect}" if merge_debug
|
|
105
|
+
dest = overwrite_unmergeables(source, dest, options)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
elsif source.kind_of?(Array)
|
|
110
|
+
puts "#{di}Arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
|
|
111
|
+
# if we are instructed, join/split any source arrays before processing
|
|
112
|
+
if array_split_char
|
|
113
|
+
puts "#{di} split/join on source: #{source.inspect}" if merge_debug
|
|
114
|
+
source = source.join(array_split_char).split(array_split_char)
|
|
115
|
+
if dest.kind_of?(Array)
|
|
116
|
+
dest = dest.join(array_split_char).split(array_split_char)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
# if there's a naked knockout_prefix in source, that means we are to truncate dest
|
|
120
|
+
if source.index(knockout_prefix)
|
|
121
|
+
dest = clear_or_nil(dest); source.delete(knockout_prefix)
|
|
122
|
+
end
|
|
123
|
+
if dest.kind_of?(Array) and ! overwrite_arrays
|
|
124
|
+
if knockout_prefix
|
|
125
|
+
print "#{di} knocking out: " if merge_debug
|
|
126
|
+
# remove knockout prefix items from both source and dest
|
|
127
|
+
source.delete_if do |ko_item|
|
|
128
|
+
retval = false
|
|
129
|
+
item = ko_item.respond_to?(:gsub) ? ko_item.gsub(%r{^#{knockout_prefix}}, "") : ko_item
|
|
130
|
+
if item != ko_item
|
|
131
|
+
print "#{ko_item} - " if merge_debug
|
|
132
|
+
dest.delete(item)
|
|
133
|
+
dest.delete(ko_item)
|
|
134
|
+
retval = true
|
|
135
|
+
end
|
|
136
|
+
retval
|
|
137
|
+
end
|
|
138
|
+
puts if merge_debug
|
|
139
|
+
end
|
|
140
|
+
puts "#{di} merging arrays: #{source.inspect} :: #{dest.inspect}" if merge_debug
|
|
141
|
+
dest = dest | source
|
|
142
|
+
dest.sort! if sort_merged_arrays
|
|
143
|
+
elsif overwrite_unmergeable or overwrite_arrays
|
|
144
|
+
puts "#{di} overwriting dest: #{source.inspect} -over-> #{dest.inspect}" if merge_debug
|
|
145
|
+
dest = overwrite_unmergeables(source, dest, options)
|
|
146
|
+
end
|
|
147
|
+
else # src_hash is not an array or hash, so we'll have to overwrite dest
|
|
148
|
+
puts "#{di}Others: #{source.inspect} :: #{dest.inspect}" if merge_debug
|
|
149
|
+
dest = overwrite_unmergeables(source, dest, options)
|
|
150
|
+
end
|
|
151
|
+
puts "#{di}Returning #{dest.inspect}" if merge_debug
|
|
152
|
+
dest
|
|
153
|
+
end # deep_merge!
|
|
154
|
+
|
|
155
|
+
# allows deep_merge! to uniformly handle overwriting of unmergeable entities
|
|
156
|
+
def self.overwrite_unmergeables(source, dest, options)
|
|
157
|
+
merge_debug = options[:merge_debug] || false
|
|
158
|
+
overwrite_unmergeable = !options[:preserve_unmergeables]
|
|
159
|
+
knockout_prefix = options[:knockout_prefix] || false
|
|
160
|
+
di = options[:debug_indent] || ''
|
|
161
|
+
if knockout_prefix && overwrite_unmergeable
|
|
162
|
+
if source.kind_of?(String) # remove knockout string from source before overwriting dest
|
|
163
|
+
if options[:overwrite_arrays] # Don't knock out strings for OATs
|
|
164
|
+
src_tmp = source
|
|
165
|
+
else
|
|
166
|
+
src_tmp = source.gsub(%r{^#{knockout_prefix}},"")
|
|
167
|
+
end
|
|
168
|
+
elsif source.kind_of?(Array) # remove all knockout elements before overwriting dest
|
|
169
|
+
src_tmp = source.delete_if {|ko_item| ko_item.kind_of?(String) && ko_item.match(%r{^#{knockout_prefix}}) }
|
|
170
|
+
else
|
|
171
|
+
src_tmp = source
|
|
172
|
+
end
|
|
173
|
+
if src_tmp == source # if we didn't find a knockout_prefix then we just overwrite dest
|
|
174
|
+
puts "#{di}#{src_tmp.inspect} -over-> #{dest.inspect}" if merge_debug
|
|
175
|
+
dest = src_tmp
|
|
176
|
+
else # if we do find a knockout_prefix, then we just delete dest
|
|
177
|
+
puts "#{di}\"\" -over-> #{dest.inspect}" if merge_debug
|
|
178
|
+
dest = ""
|
|
179
|
+
end
|
|
180
|
+
elsif overwrite_unmergeable
|
|
181
|
+
dest = source
|
|
182
|
+
end
|
|
183
|
+
dest
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def self.clear_or_nil(obj)
|
|
187
|
+
if obj.respond_to?(:clear)
|
|
188
|
+
obj.clear
|
|
189
|
+
else
|
|
190
|
+
obj = nil
|
|
191
|
+
end
|
|
192
|
+
obj
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
end # module DeepMerge
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'deep_merge/deep_merge_hash'
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'deep_merge/core'
|
|
2
|
+
|
|
3
|
+
module DeepMerge
|
|
4
|
+
module DeepMergeHash
|
|
5
|
+
# ko_hash_merge! will merge and knockout elements prefixed with DEFAULT_FIELD_KNOCKOUT_PREFIX
|
|
6
|
+
def ko_deep_merge!(source, options = {})
|
|
7
|
+
default_opts = {:knockout_prefix => "--", :preserve_unmergeables => false}
|
|
8
|
+
DeepMerge::deep_merge!(source, self, default_opts.merge(options))
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# deep_merge! will merge and overwrite any unmergeables in destination hash
|
|
12
|
+
def deep_merge!(source, options = {})
|
|
13
|
+
default_opts = {:preserve_unmergeables => false}
|
|
14
|
+
DeepMerge::deep_merge!(source, self, default_opts.merge(options))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# deep_merge will merge and skip any unmergeables in destination hash
|
|
18
|
+
def deep_merge(source, options = {})
|
|
19
|
+
default_opts = {:preserve_unmergeables => true}
|
|
20
|
+
DeepMerge::deep_merge!(source, self, default_opts.merge(options))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end # DeepMergeHashExt
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class Hash
|
|
27
|
+
include DeepMerge::DeepMergeHash
|
|
28
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'deep_merge/core'
|
|
2
|
+
|
|
3
|
+
module DeepMerge
|
|
4
|
+
module RailsCompat
|
|
5
|
+
# ko_hash_merge! will merge and knockout elements prefixed with DEFAULT_FIELD_KNOCKOUT_PREFIX
|
|
6
|
+
def ko_deeper_merge!(source, options = {})
|
|
7
|
+
default_opts = {:knockout_prefix => "--", :preserve_unmergeables => false}
|
|
8
|
+
DeepMerge::deep_merge!(source, self, default_opts.merge(options))
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# deep_merge! will merge and overwrite any unmergeables in destination hash
|
|
12
|
+
def deeper_merge!(source, options = {})
|
|
13
|
+
default_opts = {:preserve_unmergeables => false}
|
|
14
|
+
DeepMerge::deep_merge!(source, self, default_opts.merge(options))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# deep_merge will merge and skip any unmergeables in destination hash
|
|
18
|
+
def deeper_merge(source, options = {})
|
|
19
|
+
default_opts = {:preserve_unmergeables => true}
|
|
20
|
+
DeepMerge::deep_merge!(source, self, default_opts.merge(options))
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class Hash
|
|
26
|
+
include ::DeepMerge::RailsCompat
|
|
27
|
+
end
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
require 'timeout'
|
|
2
|
+
require 'oats/ossh'
|
|
3
|
+
# Returns all the matching IPs from the listed logs
|
|
4
|
+
|
|
5
|
+
class ApplicationLogs
|
|
6
|
+
|
|
7
|
+
@@app_logs_error_getter = {} # webHostName => ApplicationLogs objects
|
|
8
|
+
@@ip = nil
|
|
9
|
+
@@plink_cmd_params = {} # webHostName => Extra parameters to connect or ''
|
|
10
|
+
PLINK_TIMEOUT = 5
|
|
11
|
+
|
|
12
|
+
# Call returns only errors occurring after the previous call.
|
|
13
|
+
def ApplicationLogs.new_errors(initial = false)
|
|
14
|
+
logs = $oats['env']['web']['logs']
|
|
15
|
+
logs = nil if logs.nil? or logs.empty?
|
|
16
|
+
return [] unless logs
|
|
17
|
+
host = $oats['env']['web']['host']
|
|
18
|
+
if @@app_logs_error_getter[host]
|
|
19
|
+
return [] if initial
|
|
20
|
+
else
|
|
21
|
+
@@app_logs_error_getter[host] = ApplicationLogs.new(host,logs)
|
|
22
|
+
end
|
|
23
|
+
return @@app_logs_error_getter[host].new_errors
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def initialize(host,logs)
|
|
27
|
+
ApplicationLogs.set_ip unless @@ip
|
|
28
|
+
@logs = logs
|
|
29
|
+
@log_error_count = []
|
|
30
|
+
@command = "plink #{host} -l loguser sudo grep -i #{@@ip} " + @logs.join(' ')
|
|
31
|
+
ApplicationLogs.set_plink_cmd_params
|
|
32
|
+
@command_issue = @command
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def new_errors
|
|
36
|
+
$log.debug "Interrogating the application logs: #{@command_issue}"
|
|
37
|
+
errors = IO.popen(@command).readlines
|
|
38
|
+
total_errors = 0
|
|
39
|
+
@log_error_count.each {|i| total_errors += i}
|
|
40
|
+
new_error = []
|
|
41
|
+
return new_error if total_errors == errors.length
|
|
42
|
+
i = 0
|
|
43
|
+
new_error_count = []
|
|
44
|
+
new_error_count[0] = 0
|
|
45
|
+
errors.each do |line|
|
|
46
|
+
prefix = Regexp.new('^'+@logs[i]+':')
|
|
47
|
+
unless prefix =~ line
|
|
48
|
+
@log_error_count[i] = new_error_count[i]
|
|
49
|
+
i += 1
|
|
50
|
+
break if i == @logs.length
|
|
51
|
+
new_error_count[i] = 0
|
|
52
|
+
redo
|
|
53
|
+
end
|
|
54
|
+
new_error_count[i] += 1
|
|
55
|
+
new_error << line if new_error_count[i] > (@log_error_count[i] ? @log_error_count[i] : 0)
|
|
56
|
+
end
|
|
57
|
+
@log_error_count[i] = new_error_count[i]
|
|
58
|
+
return new_error
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Tails logs continuously.
|
|
62
|
+
def ApplicationLogs.tail_errors
|
|
63
|
+
tail_ip = $oats['execution']['tail_logs_ip']
|
|
64
|
+
logs = $oats['env']['web']['logs']
|
|
65
|
+
logs = nil if logs.nil? or logs.empty?
|
|
66
|
+
host = $oats['env']['web']['host']
|
|
67
|
+
if tail_ip
|
|
68
|
+
raise(OatsBadInput, "The execution:tail_logs_ip is set to [#{tail_ip}] but env:web:logs is empty.") unless logs
|
|
69
|
+
else
|
|
70
|
+
return
|
|
71
|
+
end
|
|
72
|
+
if tail_ip and tail_ip.instance_of?(String)
|
|
73
|
+
if /^\d\d\.\d\d*\.\d\d*\.\d\d*$/ =~ tail_ip
|
|
74
|
+
@@ip = tail_ip
|
|
75
|
+
else
|
|
76
|
+
raise(OatsBadInput, "Input for execution:tail_logs_ip [#{tail_ip}] is not in proper IP format.")
|
|
77
|
+
end
|
|
78
|
+
else
|
|
79
|
+
ApplicationLogs.set_ip unless @@ip
|
|
80
|
+
end
|
|
81
|
+
ApplicationLogs.set_plink_cmd_params(true)
|
|
82
|
+
command = "plink #{host} -l loguser sudo tail -f " + logs.join(' ')
|
|
83
|
+
command_issue = command
|
|
84
|
+
puts "Filtering for [#{@@ip}] after executing command: #{command}"
|
|
85
|
+
IO.popen(command_issue) do |io|
|
|
86
|
+
while io.gets do
|
|
87
|
+
puts $_ if Regexp.new(@@ip) =~ $_ or /^==>/ =~ $_
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
exit 0 # Should never get here. User has to kill the process to quit
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def ApplicationLogs.set_plink_cmd_params(from_tail = nil)
|
|
94
|
+
host = $oats['env']['web']['host']
|
|
95
|
+
return if @@plink_cmd_params[host]
|
|
96
|
+
# Ossh does not support this option anymore. Must go in via Paegant
|
|
97
|
+
# Clean-up the code below later.
|
|
98
|
+
@@plink_cmd_params = ''
|
|
99
|
+
error = 0
|
|
100
|
+
error_msg = nil
|
|
101
|
+
error_msg2 = nil
|
|
102
|
+
correct_response = false
|
|
103
|
+
cmd_issue = "plink #{host} -l loguser whoami 2>&1"
|
|
104
|
+
cmd_display = cmd_issue
|
|
105
|
+
$log.debug "Issuing: " + cmd_issue
|
|
106
|
+
$log.debug "Please start Paegant with loguser key if there is no response in {PLINK_TIMEOUT} seconds."
|
|
107
|
+
begin
|
|
108
|
+
timeout(PLINK_TIMEOUT) do
|
|
109
|
+
IO.popen(cmd_issue) do |ios|
|
|
110
|
+
while ios.gets(':') do
|
|
111
|
+
if /s password:/ =~ $_
|
|
112
|
+
error = 1
|
|
113
|
+
error_msg = "Received Plink authentication challenge from "
|
|
114
|
+
error_msg2 = "If you have not started Paegant already, please do so."
|
|
115
|
+
elsif /s password:/ =~ $_
|
|
116
|
+
error = 2
|
|
117
|
+
error_msg = "Received Plink authentication challenge from "
|
|
118
|
+
error_msg2 = "If you have not defined an entry for [#{host} on Putty already, please do so."
|
|
119
|
+
elsif /^Password:/ =~ $_
|
|
120
|
+
error = 3
|
|
121
|
+
error_msg = "Received 'sudo root' authentication challenge from "
|
|
122
|
+
error_msg2 = "Sudo password cash has timed out. Please type the following on a shell commandline: #{cmd_display}"
|
|
123
|
+
elsif /^Unable to open connection:/ =~ $_
|
|
124
|
+
error = 4
|
|
125
|
+
error_msg = "Could not connect to "
|
|
126
|
+
error_msg2 = "You need to unset error log interrogation to run this test in this environment."
|
|
127
|
+
# elsif /^root/ =~ $_
|
|
128
|
+
elsif /^loguser/ =~ $_
|
|
129
|
+
correct_response = true
|
|
130
|
+
end
|
|
131
|
+
$log.error $_ unless $_.nil? or correct_response
|
|
132
|
+
ios.gets
|
|
133
|
+
$log.error $_ unless $_.nil? or correct_response
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
rescue Timeout::Error
|
|
138
|
+
$log.error "plink command timed out after [#{PLINK_TIMEOUT}] seconds."
|
|
139
|
+
end
|
|
140
|
+
if error == 0 and correct_response
|
|
141
|
+
$log.info "Received proper response from Plink."
|
|
142
|
+
return
|
|
143
|
+
else
|
|
144
|
+
if error_msg
|
|
145
|
+
if error_msg2
|
|
146
|
+
$log.error error_msg + "[#{host}]"
|
|
147
|
+
else
|
|
148
|
+
raise(OatsSetupError,error_msg)
|
|
149
|
+
end
|
|
150
|
+
raise(OatsSetupError,error_msg2)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def ApplicationLogs.set_ip
|
|
156
|
+
IO.popen('ipconfig') do |io|
|
|
157
|
+
while io.gets do
|
|
158
|
+
@@ip = $_.chomp.sub(/.*IP Address.*: (\d.*\d).*/,'\1') if /IP Address.*: / =~ $_
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Should be overridden by the user if desired
|
|
2
|
+
module Oats
|
|
3
|
+
|
|
4
|
+
module BuildId
|
|
5
|
+
def BuildId.generate
|
|
6
|
+
return
|
|
7
|
+
dir_results = $oats['execution']['dir_results']
|
|
8
|
+
env_name = $oats['env']['name']
|
|
9
|
+
return unless env_name and $oats['execution']['build_version']
|
|
10
|
+
TestList.current.variations.last.env_name = env_name
|
|
11
|
+
run_info_file = File.join(dir_results,'run_info_' + env_name + '.txt')
|
|
12
|
+
unless File.exist?(run_info_file)
|
|
13
|
+
File.open(run_info_file, 'w') do |f|
|
|
14
|
+
YAML.dump($oats,f)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
if Oats.context['build_version'] # Collected build data previously
|
|
18
|
+
return if Oats.context['build_version']['execution'] == $oats['execution']['build_version'] # no change
|
|
19
|
+
Oats.context['build_version']['execution'] = $oats['execution']['build_version'] # Use the latest, input from test list
|
|
20
|
+
return
|
|
21
|
+
end
|
|
22
|
+
# First time collecting build data
|
|
23
|
+
Oats.context['build_version'] = { 'execution' => $oats['execution']['build_version'] }
|
|
24
|
+
all_build_info = ''
|
|
25
|
+
build_id_file = File.join(dir_results,'buildID_' + env_name + '.txt')
|
|
26
|
+
|
|
27
|
+
for host in $oats['execution']['build_versions'] do
|
|
28
|
+
web_host = $oats['env'][host] && $oats['env'][host]['host']
|
|
29
|
+
next unless web_host
|
|
30
|
+
urls = $oats['env'][host]['buildID_url']
|
|
31
|
+
next unless urls
|
|
32
|
+
urls = [ urls ] unless urls.instance_of? Array
|
|
33
|
+
versions = ''
|
|
34
|
+
urls.each do |url|
|
|
35
|
+
begin
|
|
36
|
+
if RUBY_VERSION =~ /^1.9/
|
|
37
|
+
resp = Net::HTTP.new(web_host, 80).get(url) # 1.9 doesn't like the second parameter
|
|
38
|
+
else
|
|
39
|
+
resp = Net::HTTP.new(web_host, 80).get(url, nil )
|
|
40
|
+
end
|
|
41
|
+
build_info = resp.body if resp.code == '200'
|
|
42
|
+
rescue
|
|
43
|
+
$log.error $!.to_s
|
|
44
|
+
$log.error "Occurred after issuing get request to [http://#{web_host}#{url}]"
|
|
45
|
+
build_info = nil
|
|
46
|
+
end
|
|
47
|
+
if build_info
|
|
48
|
+
versions += ' ' unless versions == ''
|
|
49
|
+
versions += build_info[6..(build_info.index("\n")-1)]
|
|
50
|
+
all_build_info += "--- #{host} #{url} --- \n" + build_info + "\n"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
Oats.context['build_version'][host] = versions
|
|
54
|
+
end if $oats['execution']['build_versions']
|
|
55
|
+
File.open(build_id_file, 'w') { |f| f.puts all_build_info } unless all_build_info == ''
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|