workEnv 0.1.0
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/LICENSE +620 -0
- data/bin/wenv +10 -0
- data/lib/WorkEnvs/Action.rb +604 -0
- data/lib/WorkEnvs/Common/Arch.rb +185 -0
- data/lib/WorkEnvs/Common/Config.rb +364 -0
- data/lib/WorkEnvs/Common/Confirm.rb +80 -0
- data/lib/WorkEnvs/Common/DBInterface.rb +608 -0
- data/lib/WorkEnvs/Common/Defines.rb +20 -0
- data/lib/WorkEnvs/Common/Dependencies.rb +206 -0
- data/lib/WorkEnvs/Common/EnvOpts.rb +129 -0
- data/lib/WorkEnvs/Common/Package.rb +116 -0
- data/lib/WorkEnvs/Common/PackageDownloader.rb +760 -0
- data/lib/WorkEnvs/Common/VersionSelector.rb +278 -0
- data/lib/WorkEnvs/Common.rb +10 -0
- data/lib/WorkEnvs/Core.rb +1004 -0
- data/lib/WorkEnvs/Envs/Any.rb +49 -0
- data/lib/WorkEnvs/Envs/Basic.rb +204 -0
- data/lib/WorkEnvs/accessors.rb +147 -0
- data/lib/WorkEnvs/global.rb +749 -0
- data/lib/WorkEnvs.rb +75 -0
- data/workrc-completion.sh +284 -0
- metadata +65 -0
|
@@ -0,0 +1,608 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
if !ENV["WENV_WITHSQL"].nil? then
|
|
3
|
+
begin
|
|
4
|
+
# Load MySQL2 module
|
|
5
|
+
require 'mysql2'
|
|
6
|
+
#Ugly hack not to laod MySQL2 if we really want to test MySQL1
|
|
7
|
+
raise LoadError if !ENV["WENV_FORCE_SQL1"].nil?
|
|
8
|
+
raise ("Version 0.4.1 of Mysql2 is broken. Please use another version") if Mysql2::VERSION == "0.4.1"
|
|
9
|
+
rescue LoadError
|
|
10
|
+
begin
|
|
11
|
+
require 'mysql'
|
|
12
|
+
rescue LoadError
|
|
13
|
+
raise("Neither ruby-mysql nor ruby-mysql2 are available on this system")
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
begin
|
|
17
|
+
require 'sqlite3'
|
|
18
|
+
rescue LoadError
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
require 'uri'
|
|
22
|
+
require_relative 'PackageDownloader'
|
|
23
|
+
|
|
24
|
+
module WorkEnvs
|
|
25
|
+
# Empty 2D array to to return when select provided no results
|
|
26
|
+
WORK_EMPTY_QUERY = [[nil]]
|
|
27
|
+
|
|
28
|
+
# Max number of retrying a query. Used to handle bad connections
|
|
29
|
+
MAX_ERROR_RETRY = 3
|
|
30
|
+
|
|
31
|
+
# Maximum duration of a SQL query before trigging a warning when #DEBUG_QUERIES is true
|
|
32
|
+
WENV_SLOW_QUERY_THRESHOLD = 1e-0
|
|
33
|
+
|
|
34
|
+
# Flag to enable tracking of slow queries
|
|
35
|
+
DEBUG_QUERIES = ((ENV["DEBUG_QUERIES"] != nil) ? true: false)
|
|
36
|
+
|
|
37
|
+
# Exception thrown when executing a query on a DB object failed
|
|
38
|
+
class QueryErrorException < StandardError
|
|
39
|
+
# Constructor
|
|
40
|
+
#
|
|
41
|
+
# - query is the query string that caused the failure
|
|
42
|
+
# - table is the table on which the query was executed
|
|
43
|
+
# - msg is an additional error message to print (default = nil)
|
|
44
|
+
def initialize(query, table, msg=nil)
|
|
45
|
+
super("\nERROR: Error while executing query:\n" + query.to_s(table) + "\n" + msg.to_s)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Exception thrown when executing a select query did not returned any results
|
|
50
|
+
class EmptyQueryException < StandardError
|
|
51
|
+
# Constructor
|
|
52
|
+
#
|
|
53
|
+
# - query is the query string that caused the failure
|
|
54
|
+
# - table is the table on which the query was executed
|
|
55
|
+
def initialize(query, table)
|
|
56
|
+
super("\nERROR: Found no match in the database for query:\n" + query.to_s(table))
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Interface to execute DBQuery on a SQL database
|
|
61
|
+
class DBInterface
|
|
62
|
+
# Array of table names to search into (default extracted from settings)
|
|
63
|
+
attr_reader :table
|
|
64
|
+
# Object to connect to database. Abstract ruby-mysql, ruby-mysql2 or sqlite3
|
|
65
|
+
attr_reader :db
|
|
66
|
+
# When false, enable verbose mode (default = true)
|
|
67
|
+
attr_accessor :be_silent
|
|
68
|
+
|
|
69
|
+
# Convert a table string issue from the command line to an array of table
|
|
70
|
+
#
|
|
71
|
+
# - If nil or false, get the default table string from settings
|
|
72
|
+
# - If true, only use the "releases" table (legacy from --release option)
|
|
73
|
+
# - If a string, convert to an array containing the string
|
|
74
|
+
def self.toTable(table)
|
|
75
|
+
case table
|
|
76
|
+
when nil, false
|
|
77
|
+
return WorkEnvs.settings[:db][:package_default_table].split(":").
|
|
78
|
+
inject([]){|glob, t| glob + DBInterface::toTable(t)}
|
|
79
|
+
when true
|
|
80
|
+
return [ "releases" ]
|
|
81
|
+
else
|
|
82
|
+
return [ table ]
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Connect to a MySQL database
|
|
87
|
+
#
|
|
88
|
+
# Tries to connect with ruby-mysql2 (unless WENV_FORCE_SQL1)
|
|
89
|
+
# fallback to ruby-mysql
|
|
90
|
+
#
|
|
91
|
+
# Returns:
|
|
92
|
+
# - a DB connection object (nil on error)
|
|
93
|
+
# - a label with the db type (:mysql, :mysql2, :http on error)
|
|
94
|
+
def _connectMySQL(db_server, db_user, db_passwd, db_name)
|
|
95
|
+
begin
|
|
96
|
+
raise("Skip") if !ENV["WENV_FORCE_SQL1"].nil?
|
|
97
|
+
return Mysql2::Client.new(:host => db_server,
|
|
98
|
+
:username => db_user,
|
|
99
|
+
:password => db_passwd,
|
|
100
|
+
:database => db_name), :mysql2
|
|
101
|
+
rescue => e
|
|
102
|
+
end
|
|
103
|
+
begin
|
|
104
|
+
return Mysql.new(db_server, db_user, db_passwd, db_name), :mysql
|
|
105
|
+
rescue => e
|
|
106
|
+
end
|
|
107
|
+
return nil, :http
|
|
108
|
+
end
|
|
109
|
+
private :_connectMySQL
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
# Connect to a MySQL database
|
|
113
|
+
#
|
|
114
|
+
# Extract the proper settings from the settings args and call _connectMySQL
|
|
115
|
+
#
|
|
116
|
+
# Returns:
|
|
117
|
+
# - a DB connection object (nil on error)
|
|
118
|
+
# - a label with the db type (:mysql, :mysql2, :http on error)
|
|
119
|
+
def connectMySQL(settings)
|
|
120
|
+
return _connectMySQL(settings[:package_db], settings[:package_db_user], settings[:package_db_passwd],
|
|
121
|
+
settings[:package_db_db])
|
|
122
|
+
end
|
|
123
|
+
private :connectMySQL
|
|
124
|
+
|
|
125
|
+
# Default constructor
|
|
126
|
+
def initialize(machine = nil, table=nil, silent=true)
|
|
127
|
+
@settings = WorkEnvs::settings[:db]
|
|
128
|
+
|
|
129
|
+
@table = []
|
|
130
|
+
if table.instance_of?(Array) then
|
|
131
|
+
@table = table
|
|
132
|
+
elsif table.to_s == "" then
|
|
133
|
+
@table = self.class::toTable(nil)
|
|
134
|
+
else
|
|
135
|
+
@table = table.to_s.split(":").inject([]){|glob, t| glob + DBInterface::toTable(t)}
|
|
136
|
+
end
|
|
137
|
+
@be_silent = silent
|
|
138
|
+
@admin = false
|
|
139
|
+
@dbType = @settings[:package_db_proto]
|
|
140
|
+
|
|
141
|
+
case @settings[:package_db_proto]
|
|
142
|
+
when :mysql
|
|
143
|
+
@db,@dbType = connectMySQL(@settings)
|
|
144
|
+
raise("Unable to connect to MySQL Database #{@settings[:package_db]}") if @db == nil
|
|
145
|
+
when :http,:https
|
|
146
|
+
@db,@dbType = connectMySQL(@settings)
|
|
147
|
+
if @dbType == :http
|
|
148
|
+
STDERR.puts "HTTP Query are not supported any more"
|
|
149
|
+
STDERR.puts "Please make sure you have ruby mysql or mysql2 installed"
|
|
150
|
+
raise("Protocol Fix")
|
|
151
|
+
end
|
|
152
|
+
when :sqlite
|
|
153
|
+
raise("SQLite DB '#{@settings[:package_db]}' not found." +
|
|
154
|
+
" Use --package-db option") if !File.exist?(@settings[:package_db])
|
|
155
|
+
begin
|
|
156
|
+
@db = SQLite3::Database.open(@settings[:package_db])
|
|
157
|
+
@admin = true
|
|
158
|
+
rescue => e
|
|
159
|
+
raise("Unable to connect to SQLite Database #{@settings[:package_db]}: #{e.to_s}")
|
|
160
|
+
end
|
|
161
|
+
else
|
|
162
|
+
raise("Unsupported DB protocol #{@settings[:package_db_proto].to_s}")
|
|
163
|
+
end
|
|
164
|
+
puts "Connected to DB '#{@settings[:package_db]}' using #{@dbType.to_s}" if @be_silent != true
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Switch the DB connection to an "admin" mode where insert are possible
|
|
168
|
+
#
|
|
169
|
+
# Note does not work with SQLite DB
|
|
170
|
+
def doAdminConnect(db_user = @settings[:package_db_user],
|
|
171
|
+
db_passwd = @settings[:package_db_passwd],
|
|
172
|
+
db_server = @settings[:package_db],
|
|
173
|
+
db_name = @settings[:package_db_db])
|
|
174
|
+
@db, @dbType = _connectMySQL(db_server, db_user, db_passwd, db_name)
|
|
175
|
+
raise("Failed to connect as Admin to the database") if @db == nil
|
|
176
|
+
@admin = true
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Execute a DBQuery insert query
|
|
180
|
+
#
|
|
181
|
+
# Throw EmptyQueryException on error
|
|
182
|
+
# Returns an error string if DBInterface is not in admin mode
|
|
183
|
+
def doInsert(query)
|
|
184
|
+
return "Admin mode must be enable before inserting..." if @admin != true
|
|
185
|
+
hasInfo = false
|
|
186
|
+
query.cond.each(){|el| hasInfo == true if el[:field] == "info" && el[:value].to_s != "" }
|
|
187
|
+
query.cond << { :field => "info", :value => `date`.chomp()} if hasInfo == false
|
|
188
|
+
begin
|
|
189
|
+
doQueryInternal(query, @table)
|
|
190
|
+
rescue EmptyQueryException
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# Execute a DBDepsQuery insert query
|
|
195
|
+
#
|
|
196
|
+
# Admin mode is not required
|
|
197
|
+
#
|
|
198
|
+
# Returns an error string if DBInterface is not in admin mode
|
|
199
|
+
def doInsertDep(query)
|
|
200
|
+
begin
|
|
201
|
+
doQueryInternal(query, [ "dependencies" ])
|
|
202
|
+
rescue EmptyQueryException
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Convert results generated by the @db object while executing a query into
|
|
207
|
+
# an 2 dimensional array [result_id][field]
|
|
208
|
+
#
|
|
209
|
+
# Throws EmptyQueryException if there are no results
|
|
210
|
+
# Throws QueryErrorException on internal error
|
|
211
|
+
def extractResults(query, table, result, dbType)
|
|
212
|
+
case dbType
|
|
213
|
+
when :mysql
|
|
214
|
+
raise EmptyQueryException.new(query, table) if result.nil? or result.num_rows < 1
|
|
215
|
+
fieldPos={}; idx = 0
|
|
216
|
+
result.result_metadata.fetch_fields.each() { |field|
|
|
217
|
+
fieldPos[field.name] = idx
|
|
218
|
+
idx +=1
|
|
219
|
+
}
|
|
220
|
+
resultTable = []
|
|
221
|
+
result.each(){|line|
|
|
222
|
+
resultEntry = []
|
|
223
|
+
query.qtype.map{ |x|
|
|
224
|
+
resultEntry << "#{line[fieldPos[x]]}"
|
|
225
|
+
}
|
|
226
|
+
resultTable << resultEntry
|
|
227
|
+
}
|
|
228
|
+
return resultTable
|
|
229
|
+
when :sqlite
|
|
230
|
+
raise EmptyQueryException.new(query, table) if result.nil?
|
|
231
|
+
|
|
232
|
+
hasResult = false
|
|
233
|
+
|
|
234
|
+
fieldPos={}; idx = 0
|
|
235
|
+
resultTable = []
|
|
236
|
+
result.each(){|line|
|
|
237
|
+
hasResult = true
|
|
238
|
+
resultTable << line
|
|
239
|
+
}
|
|
240
|
+
raise EmptyQueryException.new(query, table) if !hasResult
|
|
241
|
+
return resultTable
|
|
242
|
+
when :mysql2
|
|
243
|
+
if result.nil? or result.count < 1
|
|
244
|
+
raise EmptyQueryException.new(query, table)
|
|
245
|
+
else
|
|
246
|
+
resultTable=[]
|
|
247
|
+
result.each(){|row|
|
|
248
|
+
resultEntry=[]
|
|
249
|
+
query.qtype.each(){|field|
|
|
250
|
+
resultEntry << row[field]
|
|
251
|
+
}
|
|
252
|
+
resultTable << resultEntry
|
|
253
|
+
}
|
|
254
|
+
return resultTable
|
|
255
|
+
end
|
|
256
|
+
when :http
|
|
257
|
+
file = result
|
|
258
|
+
breakExpr = "-e 's/<[bB][rR][[:space:]]*\\/>/\\n/g'"
|
|
259
|
+
result = runCmd("sed -e 's/.*<BODY>//' -e 's/<\\/BODY>.*//' #{breakExpr} #{file}", @be_silent)
|
|
260
|
+
runCmd("rm -f #{file}", @be_silent)
|
|
261
|
+
if result == "Error querying DB"
|
|
262
|
+
raise QueryErrorException.new(query, table)
|
|
263
|
+
elsif result == "Error not found"
|
|
264
|
+
raise EmptyQueryException.new(query, table)
|
|
265
|
+
end
|
|
266
|
+
resultTable = []
|
|
267
|
+
result.split(/[\n,]/).each(){|line|
|
|
268
|
+
resultEntry = line.split(" ")
|
|
269
|
+
resultTable << resultEntry
|
|
270
|
+
}
|
|
271
|
+
return resultTable
|
|
272
|
+
else
|
|
273
|
+
raise("Internal error")
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
private :extractResults
|
|
277
|
+
|
|
278
|
+
# Internal function to execute a DBQuery (or any class inherting it)
|
|
279
|
+
#
|
|
280
|
+
# Convert the DBQuery into string (+ arg) and run the query.
|
|
281
|
+
#
|
|
282
|
+
# Returns result process by extractResults (two dimensional array)
|
|
283
|
+
# Throw QueryErrorException @db failed to execute the query
|
|
284
|
+
#
|
|
285
|
+
# Note: by setting the env variable DEBUG_QUERIES, it will print a message
|
|
286
|
+
# if queries are slower than WENV_SLOW_QUERY_THRESHOLD
|
|
287
|
+
def doQueryInternal(query, tables)
|
|
288
|
+
result=nil
|
|
289
|
+
startTime=Time.now()
|
|
290
|
+
case @dbType
|
|
291
|
+
when :mysql
|
|
292
|
+
queryStr, args = query.to_sql(tables)
|
|
293
|
+
begin
|
|
294
|
+
db_query = @db.prepare(queryStr)
|
|
295
|
+
puts query.to_s(tables) if @be_silent != true
|
|
296
|
+
result = db_query.execute(*args)
|
|
297
|
+
rescue => e
|
|
298
|
+
raise QueryErrorException.new(query, tables, e.to_s)
|
|
299
|
+
end
|
|
300
|
+
when :sqlite
|
|
301
|
+
queryStr, args = query.to_sql(tables)
|
|
302
|
+
begin
|
|
303
|
+
db_query = @db.prepare(queryStr)
|
|
304
|
+
puts query.to_s(tables) if @be_silent != true
|
|
305
|
+
result = db_query.execute(*args)
|
|
306
|
+
rescue => e
|
|
307
|
+
raise QueryErrorException.new(query, tables, e.to_s)
|
|
308
|
+
end
|
|
309
|
+
when :mysql2
|
|
310
|
+
queryStr = query.to_sql2(tables)
|
|
311
|
+
begin
|
|
312
|
+
puts query.to_s(tables) if @be_silent != true
|
|
313
|
+
result = @db.query(queryStr)
|
|
314
|
+
rescue => e
|
|
315
|
+
p e
|
|
316
|
+
raise QueryErrorException.new(query, tables, e.to_s)
|
|
317
|
+
end
|
|
318
|
+
else
|
|
319
|
+
raise("Internal error")
|
|
320
|
+
end
|
|
321
|
+
endTime = Time.now()
|
|
322
|
+
if DEBUG_QUERIES and (endTime - startTime) > WENV_SLOW_QUERY_THRESHOLD then
|
|
323
|
+
STDERR.puts "# Warning slow query (#{endTime - startTime})"
|
|
324
|
+
puts "#\t" + query.to_s(tables)
|
|
325
|
+
end
|
|
326
|
+
return extractResults(query, tables, result, @dbType)
|
|
327
|
+
end
|
|
328
|
+
private :doQueryInternal
|
|
329
|
+
|
|
330
|
+
# Execute a DBQuery select query
|
|
331
|
+
#
|
|
332
|
+
# Calls doQueryInternal
|
|
333
|
+
#
|
|
334
|
+
# - If all_tables is true, query is ran on the provided tables and
|
|
335
|
+
# all the table referenced as valid in the settings
|
|
336
|
+
# - If all_tables is false the query is only ran on the provided tables
|
|
337
|
+
#
|
|
338
|
+
# Throws EmptyQueryException if required = true and no results were returned
|
|
339
|
+
# Throws QueryErrorException if the query failed
|
|
340
|
+
#
|
|
341
|
+
# Returns a two dimensionnal array containing the results
|
|
342
|
+
def doQuery(query, required = true, all_tables = true, tables = @table)
|
|
343
|
+
raise("Invalid query object") if query.class != DBQuery && query.class != DBDepsQuery
|
|
344
|
+
e = nil
|
|
345
|
+
result = nil
|
|
346
|
+
|
|
347
|
+
if all_tables == true then
|
|
348
|
+
tables += @settings[:package_db_tables]
|
|
349
|
+
tables.uniq!
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
count = 0
|
|
353
|
+
begin
|
|
354
|
+
begin
|
|
355
|
+
count = count + 1
|
|
356
|
+
result = doQueryInternal(query, tables)
|
|
357
|
+
puts "Result: #{result.join("\n")}" if @be_silent != true
|
|
358
|
+
|
|
359
|
+
rescue EmptyQueryException => e
|
|
360
|
+
puts "Result: <none>" if @be_silent != true
|
|
361
|
+
rescue QueryErrorException => e
|
|
362
|
+
puts "Query Error" if @be_silent != true
|
|
363
|
+
end
|
|
364
|
+
end while e.class == QueryErrorException && count < MAX_ERROR_RETRY
|
|
365
|
+
raise e if e.class == QueryErrorException
|
|
366
|
+
|
|
367
|
+
return result if result != nil
|
|
368
|
+
|
|
369
|
+
if required != false
|
|
370
|
+
raise EmptyQueryException.new(query, table)
|
|
371
|
+
else
|
|
372
|
+
return WORK_EMPTY_QUERY
|
|
373
|
+
end
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
# Wrapper around doQuery to query DBDepsQuery
|
|
377
|
+
#
|
|
378
|
+
# Calls doQuery with the appropriate settings
|
|
379
|
+
def doDepQuery(query)
|
|
380
|
+
return doQuery(query, true, false, [ "dependencies" ])
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
# Database query
|
|
385
|
+
class DBQuery
|
|
386
|
+
# Array of DB fields allowed in conditions
|
|
387
|
+
Fields = ["sha1", "project", "name", "version", "branch", "arch"]
|
|
388
|
+
|
|
389
|
+
# Array of fields (String) to be queryed (default Fields)
|
|
390
|
+
attr_reader :qtype
|
|
391
|
+
# Hash describing matching conditions (default {})
|
|
392
|
+
# - :field => field to match in the condition
|
|
393
|
+
# - :not => IF true, checks field value is NOT value (default false)
|
|
394
|
+
# - :value => value to check against
|
|
395
|
+
# - :sub_query => DBQuery to run and check field against its results
|
|
396
|
+
#
|
|
397
|
+
# :sub_query and :value cannot be specified at the same time
|
|
398
|
+
attr_reader :cond
|
|
399
|
+
# Group result by this field (default nil)
|
|
400
|
+
attr_reader :group_by
|
|
401
|
+
# - :limit => Max number of results (default 1)
|
|
402
|
+
attr_reader :limit
|
|
403
|
+
# - :order => Field to use for sorting (default "id")
|
|
404
|
+
attr_reader :order
|
|
405
|
+
# - :orderType => Sorting order (default "ASC")
|
|
406
|
+
attr_reader :orderType
|
|
407
|
+
# - :insert => query is an insert, not a select (default false)
|
|
408
|
+
attr_reader :insert
|
|
409
|
+
|
|
410
|
+
# Constructor
|
|
411
|
+
#
|
|
412
|
+
# queryHash describe the request content
|
|
413
|
+
#
|
|
414
|
+
# Mapping is bascially @<field> = queryHash [ :<field> ]. See attributes for more infos.
|
|
415
|
+
#
|
|
416
|
+
# The constructor convert the input value into SQL compliant ones
|
|
417
|
+
def initialize(queryHash = {})
|
|
418
|
+
@qtype = Fields
|
|
419
|
+
@qtype = queryHash[:qtype] if queryHash[:qtype] != nil
|
|
420
|
+
@cond = {}
|
|
421
|
+
@cond = queryHash[:cond] if queryHash[:cond] != nil
|
|
422
|
+
@group_by = ""
|
|
423
|
+
@group_by = queryHash[:group_by] if queryHash[:group_by] != nil
|
|
424
|
+
@limit = "LIMIT 1"
|
|
425
|
+
if queryHash[:limit] == false then
|
|
426
|
+
@limit = ""
|
|
427
|
+
elsif queryHash[:limit] != nil then
|
|
428
|
+
@limit = "LIMIT " + queryHash[:limit].to_s()
|
|
429
|
+
end
|
|
430
|
+
@order = "ORDER BY id"
|
|
431
|
+
@orderType = "ASC"
|
|
432
|
+
@orderType = queryHash[:orderType] if queryHash[:orderType] != nil
|
|
433
|
+
|
|
434
|
+
if queryHash[:order] == false
|
|
435
|
+
@order = ""
|
|
436
|
+
@orderType = ""
|
|
437
|
+
elsif queryHash[:order] != nil
|
|
438
|
+
@order = "ORDER BY " + queryHash[:order].to_s()
|
|
439
|
+
end
|
|
440
|
+
@insert = false
|
|
441
|
+
@insert = queryHash[:insert] if queryHash[:insert] != nil
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
# Internal method to convert a select DBQuery to a SQL String usable with ruby-mysql or sqlite
|
|
445
|
+
#
|
|
446
|
+
# Used by to_sql
|
|
447
|
+
#
|
|
448
|
+
# Returns:
|
|
449
|
+
# - a query String
|
|
450
|
+
# - an array of arguments to be inserted in the string when executing the query
|
|
451
|
+
def to_sql_select(tables, inplace)
|
|
452
|
+
condition = ''
|
|
453
|
+
args=[]
|
|
454
|
+
if @cond != nil && @cond.length != 0 then
|
|
455
|
+
condition = 'WHERE ' + @cond.map(){|x|
|
|
456
|
+
vals = x[:value]
|
|
457
|
+
|
|
458
|
+
if vals != nil then
|
|
459
|
+
vals = [ vals ] if !vals.kind_of?(Array)
|
|
460
|
+
args += vals
|
|
461
|
+
|
|
462
|
+
(x[:not] == true ? "NOT" : "") +
|
|
463
|
+
" (" + vals.map(){|v|
|
|
464
|
+
x[:field] + " LIKE " + (inplace ? "'#{v}'" : "?")
|
|
465
|
+
}.join(" OR ") + ")"
|
|
466
|
+
else
|
|
467
|
+
"#{x[:not] == true ? "NOT" : ""} (" +
|
|
468
|
+
x[:field] + " IN #{x[:sub_query]})"
|
|
469
|
+
end
|
|
470
|
+
}.join(" AND ")
|
|
471
|
+
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
groupBy = ''
|
|
475
|
+
groupBy = "GROUP BY #{@group_by}" if @group_by.to_s != ""
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
queryStr= tables.map(){|table|
|
|
479
|
+
"( select #{@qtype.join(',')} from #{table} "+
|
|
480
|
+
"#{condition} #{groupBy} #{@order} #{@orderType} " + @limit + " )"
|
|
481
|
+
}.join(" UNION ") +
|
|
482
|
+
(tables.length > 1 && @limit.to_s != "" ? " #{@limit}" : "")
|
|
483
|
+
queryArgs = tables.inject([]){|x, y| x + args }
|
|
484
|
+
return queryStr, queryArgs
|
|
485
|
+
end
|
|
486
|
+
private :to_sql_select
|
|
487
|
+
|
|
488
|
+
# Internal method to convert an insert DBQuery to a SQL String usable with ruby-mysql or sqlite
|
|
489
|
+
#
|
|
490
|
+
# Used by to_sql
|
|
491
|
+
#
|
|
492
|
+
# Returns:
|
|
493
|
+
# - a query String
|
|
494
|
+
# - an array of arguments to be inserted in the string when executing the query
|
|
495
|
+
def to_sql_insert(tables, inplace)
|
|
496
|
+
raise("No content to insert") if @cond.empty?
|
|
497
|
+
|
|
498
|
+
queryArgs=[]
|
|
499
|
+
|
|
500
|
+
queryStr = "INSERT INTO #{tables[0]} (" +
|
|
501
|
+
@cond.map(){|el| queryArgs << el[:value]; el[:field].to_s}.join(",") + ") VALUES (" +
|
|
502
|
+
@cond.map(){|el| inplace == true ? el[:value].to_s : "?"}.join(",") + ")"
|
|
503
|
+
return queryStr, queryArgs
|
|
504
|
+
end
|
|
505
|
+
private :to_sql_insert
|
|
506
|
+
|
|
507
|
+
# Convert any DBQuery to a SQL String usable with ruby-mysql or sqlite
|
|
508
|
+
#
|
|
509
|
+
# Uses to_sql_insert or to_sql_select depending on the #insert attribute
|
|
510
|
+
#
|
|
511
|
+
# Returns:
|
|
512
|
+
# - a query String
|
|
513
|
+
# - an array of arguments to be inserted in the string when executing the query
|
|
514
|
+
def to_sql(tables, inplace=false)
|
|
515
|
+
if @insert == true then
|
|
516
|
+
to_sql_insert(tables, inplace)
|
|
517
|
+
else
|
|
518
|
+
to_sql_select(tables, inplace)
|
|
519
|
+
end
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
# Internal method to convert a select DBQuery to a SQL String usable with ruby-mysql2
|
|
523
|
+
#
|
|
524
|
+
# Used by to_sql2
|
|
525
|
+
#
|
|
526
|
+
# Returns a query String with arguments inlines
|
|
527
|
+
def to_sql2_select(tables)
|
|
528
|
+
condition = ''
|
|
529
|
+
if @cond != nil && @cond.length != 0 then
|
|
530
|
+
condition = 'WHERE ' + @cond.map(){|x|
|
|
531
|
+
|
|
532
|
+
vals = x[:value]
|
|
533
|
+
if vals != nil then
|
|
534
|
+
vals = [ vals ] if !vals.kind_of?(Array)
|
|
535
|
+
|
|
536
|
+
(x[:not] == true ? "NOT" : "") +
|
|
537
|
+
" (" + vals.map(){|v|
|
|
538
|
+
x[:field] +" LIKE '#{Mysql2::Client.escape(v.to_s)}'"
|
|
539
|
+
}.join(" OR ") + ")"
|
|
540
|
+
else
|
|
541
|
+
"#{x[:not] == true ? "NOT" : ""} (" +
|
|
542
|
+
x[:field] + " IN #{x[:sub_query]})"
|
|
543
|
+
end
|
|
544
|
+
}.join(" AND ")
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
groupBy = ''
|
|
548
|
+
groupBy = "GROUP BY #{@group_by}" if @group_by.to_s != ""
|
|
549
|
+
|
|
550
|
+
return tables.map(){|table|
|
|
551
|
+
queryStr= "select #{@qtype.join(',')} from #{table} "+
|
|
552
|
+
"#{condition} #{groupBy} #{@order} #{@orderType} " + @limit
|
|
553
|
+
"( " + queryStr + " )"
|
|
554
|
+
}.join(" UNION ") +
|
|
555
|
+
(tables.length > 1 && @limit.to_s != "" ? " #{@limit}" : "")
|
|
556
|
+
end
|
|
557
|
+
private :to_sql2_select
|
|
558
|
+
|
|
559
|
+
# Internal method to convert an insert DBQuery to a SQL String usable with ruby-mysql2
|
|
560
|
+
#
|
|
561
|
+
# Used by to_sql2
|
|
562
|
+
#
|
|
563
|
+
# Returns a query String with arguments inlines
|
|
564
|
+
def to_sql2_insert(tables)
|
|
565
|
+
raise("No content to insert") if @cond.empty?
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
queryStr = "INSERT INTO #{tables[0]}(" +
|
|
569
|
+
@cond.map(){|el| el[:field].to_s}.join(",") + ") VALUES (" +
|
|
570
|
+
@cond.map(){|el| "'" + Mysql2::Client.escape(el[:value].to_s) + "'"}.join(",") + ")"
|
|
571
|
+
return queryStr
|
|
572
|
+
end
|
|
573
|
+
private :to_sql2_insert
|
|
574
|
+
|
|
575
|
+
# Convert any DBQuery to a SQL String usable with ruby-mysql2
|
|
576
|
+
#
|
|
577
|
+
# Uses to_sql2_insert or to_sql2_select depending on the #insert attribute
|
|
578
|
+
#
|
|
579
|
+
# Returns a query String with arguments inlines
|
|
580
|
+
def to_sql2(tables)
|
|
581
|
+
if @insert == true then
|
|
582
|
+
to_sql2_insert(tables)
|
|
583
|
+
else
|
|
584
|
+
to_sql2_select(tables)
|
|
585
|
+
end
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
# Convert a query to a string for logging and exceptions
|
|
589
|
+
def to_s(tables=["??"])
|
|
590
|
+
return "Query: " + self.to_sql(tables, true)[0]
|
|
591
|
+
end
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
# Variation of DBQuery
|
|
595
|
+
#
|
|
596
|
+
# Override the Fields attribute to fir the dependency DB
|
|
597
|
+
class DBDepsQuery < DBQuery
|
|
598
|
+
# Array of Dependency DB fields allowed in conditions
|
|
599
|
+
Fields = ["name", "arch", "dependencies"]
|
|
600
|
+
# Default constructor
|
|
601
|
+
def initialize(queryHash = {})
|
|
602
|
+
super(queryHash)
|
|
603
|
+
@qtype = Fields
|
|
604
|
+
@qtype = queryHash[:qtype] if queryHash[:qtype] != nil
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
end
|
|
608
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module WorkEnvs
|
|
2
|
+
# Hostname of the current machine
|
|
3
|
+
WORK_ENV_HOSTNAME= ENV["HOSTNAME"].to_s != "" ? ENV["HOSTNAME"] :
|
|
4
|
+
(File.exist?("/usr/bin/hostname") ? `/usr/bin/hostname`.chomp() : "")
|
|
5
|
+
|
|
6
|
+
# Dir where workEnv scripts are
|
|
7
|
+
WORK_ENV_SCRIPTS_DIR=File.dirname(File.dirname(File.dirname(File.dirname(__FILE__))))
|
|
8
|
+
|
|
9
|
+
# Directory for global configuration
|
|
10
|
+
WORK_ENV_GLOBAL_DIR = (ENV["XDG_CONFIG_HOME"] != nil) ?
|
|
11
|
+
File.expand_path("#{ENV["XDG_CONFIG_HOME"]}/workEnv/"):
|
|
12
|
+
File.expand_path("~/.config/workEnv/")
|
|
13
|
+
|
|
14
|
+
# Per host cache directory within the global config directory
|
|
15
|
+
WORK_ENV_CACHE_DIR = WORK_ENV_GLOBAL_DIR + "/" + WORK_ENV_HOSTNAME
|
|
16
|
+
|
|
17
|
+
# Global flag to enable verbosity
|
|
18
|
+
VERBOSE = (ENV["VERBOSE"].to_s != "") ? true: false
|
|
19
|
+
|
|
20
|
+
end
|