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,749 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
require 'pathname'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
module WorkEnvs
|
|
6
|
+
|
|
7
|
+
# DEBUG mode.
|
|
8
|
+
#
|
|
9
|
+
# Enabled by ENV["DEBUG"] is set
|
|
10
|
+
DEBUG = ((ENV["DEBUG"] != nil) ? true: false)
|
|
11
|
+
|
|
12
|
+
# Array of all supported Environment classes
|
|
13
|
+
ENV_TYPES = WorkEnvs.constants.delete_if {|c|
|
|
14
|
+
theObject = WorkEnvs.const_get(c)
|
|
15
|
+
!(Class === theObject) ||
|
|
16
|
+
getEnvType(theObject) == nil
|
|
17
|
+
}.map(){|x| WorkEnvs.const_get(x)}
|
|
18
|
+
|
|
19
|
+
@@checkedUpdates = false
|
|
20
|
+
@@checkedEnvs = false
|
|
21
|
+
|
|
22
|
+
# Debug print macro.
|
|
23
|
+
# * Only prints if DEBUG=1
|
|
24
|
+
# * Print backtrace if bt == true
|
|
25
|
+
def dputs(str, bt = false)
|
|
26
|
+
return if DEBUG != true
|
|
27
|
+
|
|
28
|
+
puts "DEBUG: " + str
|
|
29
|
+
if bt == true then
|
|
30
|
+
puts caller
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
module_function :dputs
|
|
34
|
+
|
|
35
|
+
# More complete check of the WorkEnvs
|
|
36
|
+
# Mostly checks for coherency error within the ruby scripts themselves.
|
|
37
|
+
#
|
|
38
|
+
# This is not called automatically, unless DEBUG is set
|
|
39
|
+
def selfCheckFull()
|
|
40
|
+
return if !DEBUG
|
|
41
|
+
#Check that the envClass really redefined itself
|
|
42
|
+
global = {
|
|
43
|
+
:types => {},
|
|
44
|
+
:main => {}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
ENV_LIST.each(){|e|
|
|
48
|
+
envClass = WorkEnvs.const_get(e + "Env")
|
|
49
|
+
type = getEnvType(envClass)
|
|
50
|
+
raise("Both #{global[:types][type]} and #{envClass} use environment type '#{type}'") if global[:types][type] != nil && type != :dev
|
|
51
|
+
global[:types][type] = envClass
|
|
52
|
+
|
|
53
|
+
mains = getMainPackage(envClass)
|
|
54
|
+
mains.each(){|main|
|
|
55
|
+
if global[:main][main] != nil then
|
|
56
|
+
STDERR.puts "WARNING: Both #{global[:main][main]} and #{envClass} use the same main package '#{main}'"
|
|
57
|
+
end
|
|
58
|
+
global[:main][main] = envClass
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
module_function :selfCheckFull
|
|
64
|
+
|
|
65
|
+
# WorkEnvs global safety checks
|
|
66
|
+
# and eventual self update
|
|
67
|
+
def checkEnvs(force_update = false)
|
|
68
|
+
return if @@checkedEnvs == true
|
|
69
|
+
# Check required thing that would break everything
|
|
70
|
+
# Autocalled on requiring this file so no worries
|
|
71
|
+
selfCheckFull() if DEBUG == true
|
|
72
|
+
|
|
73
|
+
if !File.directory?(WORK_ENVS) then
|
|
74
|
+
STDERR.puts "#{WORK_ENVS} needs to be created to use Work Environments"
|
|
75
|
+
STDERR.puts "Please run: mkdir -p #{WORK_ENVS}"
|
|
76
|
+
raise("Missing #{WORK_ENVS}")
|
|
77
|
+
end
|
|
78
|
+
if !File.directory?(WORK_ENV_CACHE_DIR) then
|
|
79
|
+
runCmd("mkdir -p #{WORK_ENV_CACHE_DIR}", !VERBOSE)
|
|
80
|
+
end
|
|
81
|
+
@@checkedEnvs = true
|
|
82
|
+
end
|
|
83
|
+
module_function :checkEnvs
|
|
84
|
+
|
|
85
|
+
# Get the name of the current environment
|
|
86
|
+
def getCurrentEnvName()
|
|
87
|
+
return ENV["WORK_ENV_CURRENT"]
|
|
88
|
+
end
|
|
89
|
+
module_function :getCurrentEnvName
|
|
90
|
+
|
|
91
|
+
# Get path to the current environment
|
|
92
|
+
def getCurrentEnvPath()
|
|
93
|
+
return ENV["WORK_ENV_PATH"]
|
|
94
|
+
end
|
|
95
|
+
module_function :getCurrentEnvPath
|
|
96
|
+
|
|
97
|
+
# Get the list of all dirs to store envs
|
|
98
|
+
#
|
|
99
|
+
# Return a hash (label | :default) => dirpath
|
|
100
|
+
def getDirList()
|
|
101
|
+
settings = settings()
|
|
102
|
+
dirs = { :default => WORK_ENVS }
|
|
103
|
+
|
|
104
|
+
settings[:global][:custom_env_dirs].each{|name, dirpath|
|
|
105
|
+
next if !File.exist?(dirpath)
|
|
106
|
+
dirs[name] = dirpath
|
|
107
|
+
}
|
|
108
|
+
return dirs
|
|
109
|
+
end
|
|
110
|
+
module_function :getDirList
|
|
111
|
+
|
|
112
|
+
# Get the top dir of an env from its label
|
|
113
|
+
def getDirPathFromLabel(label)
|
|
114
|
+
return WORK_ENVS if label.to_s() == "" || label == :default
|
|
115
|
+
|
|
116
|
+
settings[:global][:custom_env_dirs].each{|d_label, dirpath|
|
|
117
|
+
return dirpath if d_label == label
|
|
118
|
+
}
|
|
119
|
+
raise("Invalid wenv directory label '#{label}'")
|
|
120
|
+
end
|
|
121
|
+
module_function :getDirPathFromLabel
|
|
122
|
+
|
|
123
|
+
# Get the label top dir from its path
|
|
124
|
+
def getDirLabelFromPath(path)
|
|
125
|
+
settings[:global][:custom_env_dirs].each{|label, dirpath|
|
|
126
|
+
return label if dirpath == path
|
|
127
|
+
}
|
|
128
|
+
return nil
|
|
129
|
+
end
|
|
130
|
+
module_function :getDirLabelFromPath
|
|
131
|
+
|
|
132
|
+
# Extract label and name from an env name string
|
|
133
|
+
#
|
|
134
|
+
# Format is label::name
|
|
135
|
+
#
|
|
136
|
+
# Returns label,name
|
|
137
|
+
#
|
|
138
|
+
# If the env is in the default dir, label=nil
|
|
139
|
+
def strToLabelName(str)
|
|
140
|
+
a = str.split("::")
|
|
141
|
+
env_name = str
|
|
142
|
+
label = nil
|
|
143
|
+
if a.length > 1 then
|
|
144
|
+
env_name = a[1]
|
|
145
|
+
label = a[0]
|
|
146
|
+
end
|
|
147
|
+
return label,env_name
|
|
148
|
+
end
|
|
149
|
+
module_function :strToLabelName
|
|
150
|
+
|
|
151
|
+
# Generate an env name string from a label and the env name
|
|
152
|
+
#
|
|
153
|
+
# Returns a string with the full name
|
|
154
|
+
def labelNameToStr(label, name)
|
|
155
|
+
if label.to_s() == "" || label == :default
|
|
156
|
+
return name
|
|
157
|
+
else
|
|
158
|
+
return label.to_s() + "::" + name.to_s()
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
module_function :labelNameToStr
|
|
162
|
+
|
|
163
|
+
# Check if the name match a valid environment
|
|
164
|
+
#
|
|
165
|
+
# This returns true wheteher the environment is switchable or not
|
|
166
|
+
def isEnv?(name)
|
|
167
|
+
checkEnvs()
|
|
168
|
+
# Does this name matches a valid environment
|
|
169
|
+
label, name = strToLabelName(name)
|
|
170
|
+
|
|
171
|
+
confFile = getDirPathFromLabel(label) + "/" + name + "/" + ENV_CONF
|
|
172
|
+
# Skip unconfigured envs
|
|
173
|
+
return false if !File.exist?(confFile)
|
|
174
|
+
return true
|
|
175
|
+
end
|
|
176
|
+
module_function :isEnv?
|
|
177
|
+
|
|
178
|
+
# Load environment from its name using loadEnv
|
|
179
|
+
#
|
|
180
|
+
# name MUST be a valid environment
|
|
181
|
+
def getEnv(name)
|
|
182
|
+
checkEnvs()
|
|
183
|
+
label, name = strToLabelName(name)
|
|
184
|
+
|
|
185
|
+
# Create an workEnv object (from it's file) using its name (must be valid)
|
|
186
|
+
path = getDirPathFromLabel(label) + "/" + name + "/" + ENV_CONF
|
|
187
|
+
env = loadEnvPath(path)
|
|
188
|
+
env.label = label if env != nil
|
|
189
|
+
return env
|
|
190
|
+
end
|
|
191
|
+
module_function :getEnv
|
|
192
|
+
|
|
193
|
+
def YAMLLoad(data)
|
|
194
|
+
|
|
195
|
+
begin
|
|
196
|
+
return YAML::load(data)
|
|
197
|
+
rescue Psych::DisallowedClass
|
|
198
|
+
# If data is a file, don't forget to rewind back to its beginning
|
|
199
|
+
data.rewind() if data.is_a?(File)
|
|
200
|
+
y = YAML::load(data,
|
|
201
|
+
permitted_classes:
|
|
202
|
+
ENV_LIST.map(){|x| WorkEnvs.const_get(x+ "Env") } +
|
|
203
|
+
[ WorkEnvs::EnvOpts, Symbol ])
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
module_function :YAMLLoad
|
|
207
|
+
|
|
208
|
+
# Load environment from a YAML file
|
|
209
|
+
# * Path points to a YAML description file
|
|
210
|
+
# * Environment are self migrated on load
|
|
211
|
+
def loadEnvPath(path)
|
|
212
|
+
migrate = false
|
|
213
|
+
desc = File.open(path, "r")
|
|
214
|
+
begin
|
|
215
|
+
env = YAMLLoad(desc)
|
|
216
|
+
rescue => e
|
|
217
|
+
raise("Failed to load environment description for environment '#{path}': #{e}")
|
|
218
|
+
end
|
|
219
|
+
desc.close()
|
|
220
|
+
|
|
221
|
+
#Check for broken Envs
|
|
222
|
+
expectedName = File.basename(File.dirname(path))
|
|
223
|
+
if env.name != expectedName then
|
|
224
|
+
STDERR.puts "ERROR: Environment internal name does not match directory name..."
|
|
225
|
+
STDERR.puts "ERROR: Directory name is '#{expectedName}'. Internal name is '#{env.name}'"
|
|
226
|
+
rep = 't'
|
|
227
|
+
while rep != "y" && rep != "n" && rep != '' do
|
|
228
|
+
puts "Do you wish to update this environment internal name to '#{expectedName} ? (y/N): "
|
|
229
|
+
rep = STDIN.gets.chomp()
|
|
230
|
+
end
|
|
231
|
+
if rep == "y" then
|
|
232
|
+
env.name = expectedName
|
|
233
|
+
env.dump()
|
|
234
|
+
else
|
|
235
|
+
raise("Cannot continue until this environment name is fixed or #{File.dirname(path)} is moved outside #{WORK_ENVS}.")
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
#Update the env if necessary
|
|
240
|
+
env = env.migrate()
|
|
241
|
+
|
|
242
|
+
return env
|
|
243
|
+
end
|
|
244
|
+
module_function :loadEnvPath
|
|
245
|
+
|
|
246
|
+
# Return the current environment object
|
|
247
|
+
def getCurrentEnv()
|
|
248
|
+
# Return the current environment in we are in one
|
|
249
|
+
|
|
250
|
+
envName = getCurrentEnvName()
|
|
251
|
+
if envName == nil || envName == "" then
|
|
252
|
+
STDERR.puts "No current environment"
|
|
253
|
+
return nil
|
|
254
|
+
end
|
|
255
|
+
dirpath = File.dirname(getCurrentEnvPath())
|
|
256
|
+
label = getDirLabelFromPath(dirpath)
|
|
257
|
+
name_str = labelNameToStr(label, envName)
|
|
258
|
+
if !isEnv?(name_str)
|
|
259
|
+
STDERR.puts "'#{curEnv} is not a valid environment"
|
|
260
|
+
return nil
|
|
261
|
+
end
|
|
262
|
+
# Load environment
|
|
263
|
+
return getEnv(name_str)
|
|
264
|
+
end
|
|
265
|
+
module_function :getCurrentEnv
|
|
266
|
+
|
|
267
|
+
# Return an array of all existing environments object
|
|
268
|
+
def getEnvs()
|
|
269
|
+
checkEnvs()
|
|
270
|
+
settings = settings()
|
|
271
|
+
|
|
272
|
+
envs=[]
|
|
273
|
+
dirs = getDirList()
|
|
274
|
+
dirs.each(){|label, dirpath|
|
|
275
|
+
Dir.foreach(dirpath).sort().each() {|dirname|
|
|
276
|
+
# Skip hidden directories
|
|
277
|
+
next if dirname[0] == "."
|
|
278
|
+
|
|
279
|
+
# Skip bad environment
|
|
280
|
+
next if !isEnv?(labelNameToStr(label, dirname))
|
|
281
|
+
|
|
282
|
+
# Load environment
|
|
283
|
+
begin
|
|
284
|
+
envs << getEnv(labelNameToStr(label, dirname))
|
|
285
|
+
rescue => e
|
|
286
|
+
# Environment might be broken. Skip
|
|
287
|
+
puts e.to_s
|
|
288
|
+
next
|
|
289
|
+
end
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return envs
|
|
293
|
+
end
|
|
294
|
+
module_function :getEnvs
|
|
295
|
+
|
|
296
|
+
# Return an array of all existing environments names
|
|
297
|
+
def getEnvNames()
|
|
298
|
+
settings = settings()
|
|
299
|
+
envs = []
|
|
300
|
+
dirs = getDirList()
|
|
301
|
+
dirs.each(){|label, dirpath|
|
|
302
|
+
Dir.foreach(dirpath).sort().each() {|dirname|
|
|
303
|
+
# Skip hidden directories
|
|
304
|
+
next if dirname[0] == "."
|
|
305
|
+
|
|
306
|
+
# Skip bad environment
|
|
307
|
+
next if !isEnv?(labelNameToStr(label, dirname))
|
|
308
|
+
envs << dirname
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return envs
|
|
312
|
+
end
|
|
313
|
+
module_function :getEnvNames
|
|
314
|
+
|
|
315
|
+
# Check if 'type' is a valid environment type
|
|
316
|
+
#
|
|
317
|
+
# type can either be String or Symbol
|
|
318
|
+
def isValidType?(type)
|
|
319
|
+
envTypes = listEnvTypes()
|
|
320
|
+
return false if envTypes[type.to_sym()] == nil
|
|
321
|
+
return true
|
|
322
|
+
end
|
|
323
|
+
module_function :isValidType?
|
|
324
|
+
|
|
325
|
+
# Check if 'name' is a valid environment name
|
|
326
|
+
def isValidName?(name)
|
|
327
|
+
# Can the name be used for an environment
|
|
328
|
+
return false if name !~ /^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/
|
|
329
|
+
return true
|
|
330
|
+
end
|
|
331
|
+
module_function :isValidName?
|
|
332
|
+
|
|
333
|
+
# Check if we can safely switch to an environment from its name
|
|
334
|
+
#
|
|
335
|
+
# This checks that the environment has contents (unless it's a dev environment),
|
|
336
|
+
# and that the versions of the files within the environment are the
|
|
337
|
+
# versions expected
|
|
338
|
+
#
|
|
339
|
+
# 'name' must be a valid name.
|
|
340
|
+
def isSwitchable?(name)
|
|
341
|
+
|
|
342
|
+
# Load the environment object
|
|
343
|
+
env = getEnv(name)
|
|
344
|
+
|
|
345
|
+
# Check that all required packages are initialized
|
|
346
|
+
return env.isSwitchable?()
|
|
347
|
+
end
|
|
348
|
+
module_function :isSwitchable?
|
|
349
|
+
|
|
350
|
+
# Convert en environment type (Symbol or String) to the
|
|
351
|
+
# associated environment Class
|
|
352
|
+
#
|
|
353
|
+
# Returns nil if none or multiple environment match
|
|
354
|
+
def symbolToClass(name)
|
|
355
|
+
envClass = listEnvs().select {|c|
|
|
356
|
+
getEnvType(c) == name.to_sym()
|
|
357
|
+
}
|
|
358
|
+
return nil if envClass == nil || envClass.length != 1
|
|
359
|
+
return envClass[0]
|
|
360
|
+
end
|
|
361
|
+
module_function :symbolToClass
|
|
362
|
+
|
|
363
|
+
# Returns an array of environment class that use
|
|
364
|
+
# 'file' as theuir REV_FILE
|
|
365
|
+
#
|
|
366
|
+
# Returns nil if no environment matches
|
|
367
|
+
def revFileToClasses(file)
|
|
368
|
+
name = File.basename(file)
|
|
369
|
+
envClasses = listEnvs().select {|c|
|
|
370
|
+
getRevFile(c) == name
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return nil if envClasses == nil || envClasses.length == 0
|
|
374
|
+
return envClasses
|
|
375
|
+
end
|
|
376
|
+
module_function :revFileToClasses
|
|
377
|
+
|
|
378
|
+
# Add all env specific options to the opt Parser
|
|
379
|
+
# so it shows up in the usage
|
|
380
|
+
def addEnvToOptParser(optsParser)
|
|
381
|
+
envHash = listEnvTypes()
|
|
382
|
+
optsParser.separator "Environment Types:"
|
|
383
|
+
envHash.each(){|sym, tClass|
|
|
384
|
+
legend = getEnvDescription(tClass)
|
|
385
|
+
char='-'
|
|
386
|
+
char='*' if sym.to_s == WORK_ENV_DEFAULT_TYPE
|
|
387
|
+
optsParser.separator(" #{char} " + sym.to_s.ljust(59) + legend)
|
|
388
|
+
}
|
|
389
|
+
end
|
|
390
|
+
module_function :addEnvToOptParser
|
|
391
|
+
|
|
392
|
+
# Return an array of all environment classes
|
|
393
|
+
def listEnvs()
|
|
394
|
+
return ENV_TYPES
|
|
395
|
+
end
|
|
396
|
+
module_function :listEnvs
|
|
397
|
+
|
|
398
|
+
# Return a hash containing environment type => environment class
|
|
399
|
+
def listEnvTypes()
|
|
400
|
+
envClass = listEnvs()
|
|
401
|
+
envHash = {}
|
|
402
|
+
envClass.each(){|theClass|
|
|
403
|
+
envHash[getEnvType(theClass)] = theClass
|
|
404
|
+
}
|
|
405
|
+
return envHash
|
|
406
|
+
end
|
|
407
|
+
module_function :listEnvTypes
|
|
408
|
+
|
|
409
|
+
# Create a memory instance of an environment
|
|
410
|
+
#
|
|
411
|
+
# * name: instance name
|
|
412
|
+
# * type: environment type
|
|
413
|
+
# * machine: hash returned by getArch() to configure the environment
|
|
414
|
+
# host/arch
|
|
415
|
+
# * release: Name of the default table in the DB to search for versions
|
|
416
|
+
#
|
|
417
|
+
# All environment are checked for validity
|
|
418
|
+
# Return a pointer to a BasicEnv object on success
|
|
419
|
+
def instantiateEnv(name, type, machine, release)
|
|
420
|
+
label, name = strToLabelName(name)
|
|
421
|
+
envClass = stringToEnvClass(type)
|
|
422
|
+
env = envClass.new(name, machine, release)
|
|
423
|
+
env.label = label
|
|
424
|
+
return env
|
|
425
|
+
end
|
|
426
|
+
module_function :instantiateEnv
|
|
427
|
+
|
|
428
|
+
# Return if an environment with this name exists
|
|
429
|
+
def existsEnv?(name)
|
|
430
|
+
checkEnvs()
|
|
431
|
+
label, name = strToLabelName(name)
|
|
432
|
+
dirpath = getDirPathFromLabel(label)
|
|
433
|
+
return File.exist?(dirpath + "/" + name) && File.exist?(dirpath + "/" + name + "/" + ENV_CONF)
|
|
434
|
+
end
|
|
435
|
+
module_function :existsEnv?
|
|
436
|
+
|
|
437
|
+
# Create an environment.
|
|
438
|
+
#
|
|
439
|
+
# * Instantiate a environment using instantiatEnv
|
|
440
|
+
# * Saves it on disk
|
|
441
|
+
def createEnv(name, type, release)
|
|
442
|
+
checkEnvs()
|
|
443
|
+
raise("Environment already exists") if existsEnv?(name) == true
|
|
444
|
+
env = instantiateEnv(name, type, nil, release)
|
|
445
|
+
dirpath = getDirPathFromLabel(env.label)
|
|
446
|
+
|
|
447
|
+
Dir.mkdir(dirpath + "/" + env.name)
|
|
448
|
+
env.dump()
|
|
449
|
+
return env
|
|
450
|
+
end
|
|
451
|
+
module_function :createEnv
|
|
452
|
+
|
|
453
|
+
# Generic code to support version selection in the opt parser
|
|
454
|
+
#
|
|
455
|
+
# * --sha1/--version
|
|
456
|
+
# * --hudson/--hudson-auto
|
|
457
|
+
# * --sub-sha1
|
|
458
|
+
# * --list/--latest
|
|
459
|
+
# * etc...
|
|
460
|
+
#
|
|
461
|
+
# Instantiate a #VersionSelector
|
|
462
|
+
def versionSelectorPrepare(opts, optsParser)
|
|
463
|
+
opts[:version_selector] = VersionSelector.new(opts, optsParser)
|
|
464
|
+
end
|
|
465
|
+
module_function :versionSelectorPrepare
|
|
466
|
+
|
|
467
|
+
# Post-Process #VersionSelector options by calling finalize()
|
|
468
|
+
def versionSelectorFinal(opts, env)
|
|
469
|
+
raise("Internal error") if opts[:version_selector] == nil
|
|
470
|
+
flags, opts[:infos], opts[:infos_extra], envOpts = opts[:version_selector].finalize(opts, env)
|
|
471
|
+
opts[:envOpts] = opts[:envOpts].concat(envOpts)
|
|
472
|
+
opts.merge!(flags)
|
|
473
|
+
end
|
|
474
|
+
module_function :versionSelectorFinal
|
|
475
|
+
|
|
476
|
+
# Remove an env from its full name (label and name)
|
|
477
|
+
#
|
|
478
|
+
# BEWARE: No confirmation !
|
|
479
|
+
def deleteEnv(name)
|
|
480
|
+
# Delete an existing environment completely !!!
|
|
481
|
+
label, name = strToLabelName(name)
|
|
482
|
+
dirpath = getDirPathFromLabel(label)
|
|
483
|
+
runCmd("chmod -R +w #{dirpath + "/" + name}", !VERBOSE)
|
|
484
|
+
runCmd("rm -Rf #{dirpath + "/" + name}", !VERBOSE)
|
|
485
|
+
end
|
|
486
|
+
module_function :deleteEnv
|
|
487
|
+
|
|
488
|
+
# Return a header to display environment lists
|
|
489
|
+
def listHeader()
|
|
490
|
+
maxLen = getEnvNames().inject(0){|x, y| x > y.length ? x : y.length}
|
|
491
|
+
return "Name".ljust(maxLen + 2) + "Type".center(20) + "Machine".center(15) +
|
|
492
|
+
"Expiration".center(15)
|
|
493
|
+
end
|
|
494
|
+
module_function :listHeader
|
|
495
|
+
|
|
496
|
+
# Return an array of all the parent env Classes of an envClass (including itself)
|
|
497
|
+
#
|
|
498
|
+
# if no_recurse is set, only return the envClass provided
|
|
499
|
+
def familyTreeListClass(objClass, no_recurse = false)
|
|
500
|
+
if no_recurse == true
|
|
501
|
+
return [ objClass ]
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
classList=[ ]
|
|
505
|
+
tmpList=[ objClass ]
|
|
506
|
+
hasBaseClass = false
|
|
507
|
+
|
|
508
|
+
while tmpList.length != 0
|
|
509
|
+
obj = tmpList.shift()
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
# Delete object first so that if it exits, we will retain the version
|
|
513
|
+
# that is the highest in the dep tree so all the analysis dependency
|
|
514
|
+
# should be done in the right order
|
|
515
|
+
classList.delete(obj)
|
|
516
|
+
|
|
517
|
+
classList.push(obj)
|
|
518
|
+
hasBaseClass = true if obj == BasicEnv
|
|
519
|
+
|
|
520
|
+
getParents(obj).each(){|parent|
|
|
521
|
+
tmpList.push(parent)
|
|
522
|
+
}
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
classList.push(BasicEnv) if hasBaseClass == false
|
|
526
|
+
return classList
|
|
527
|
+
end
|
|
528
|
+
module_function :familyTreeListClass
|
|
529
|
+
|
|
530
|
+
# Return an array of all the parent env Classes of an env (including the env class itself)
|
|
531
|
+
#
|
|
532
|
+
# Calls #familyTreeListClass
|
|
533
|
+
def familyTreeList(obj, no_recurse = false)
|
|
534
|
+
return familyTreeListClass(obj.class, no_recurse)
|
|
535
|
+
end
|
|
536
|
+
module_function :familyTreeList
|
|
537
|
+
|
|
538
|
+
# Calls a code block on each parent env Class of an env Class (including itself)
|
|
539
|
+
#
|
|
540
|
+
# If reverse is true, call from ancestors to children
|
|
541
|
+
def familyTreeApplyClass(objClass, reverse = false, no_recurse = false, &f)
|
|
542
|
+
classList = familyTreeListClass(objClass, no_recurse)
|
|
543
|
+
|
|
544
|
+
if reverse == false then
|
|
545
|
+
classList.each(){|objClass|
|
|
546
|
+
yield objClass
|
|
547
|
+
}
|
|
548
|
+
else
|
|
549
|
+
while ! classList.empty? do
|
|
550
|
+
objClass = classList.pop()
|
|
551
|
+
yield objClass
|
|
552
|
+
end
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
end
|
|
556
|
+
module_function :familyTreeApplyClass
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
# Calls a code block on each parent env Class of an env (including the env class itself)
|
|
560
|
+
#
|
|
561
|
+
# If reverse is true, call from ancestors to children
|
|
562
|
+
#
|
|
563
|
+
# Calls #familyTreeApplyClass
|
|
564
|
+
def familyTreeApply(obj, reverse = false, no_recurse=false, &f)
|
|
565
|
+
familyTreeApplyClass(obj.class, reverse, no_recurse){|_class| yield _class }
|
|
566
|
+
end
|
|
567
|
+
module_function :familyTreeApply
|
|
568
|
+
|
|
569
|
+
# Returns an array of all the env Classes that share the same repository as objClass
|
|
570
|
+
def exploreSiblings(objClass)
|
|
571
|
+
envClass = envToClass(objClass)
|
|
572
|
+
repo = getGitRepo(objClass)
|
|
573
|
+
return [ envClass ] if repo == ""
|
|
574
|
+
|
|
575
|
+
begin
|
|
576
|
+
return listEnvs().map{|e| getGitRepo(e) == repo ? e : nil}.compact()
|
|
577
|
+
rescue
|
|
578
|
+
return [ envClass ]
|
|
579
|
+
end
|
|
580
|
+
end
|
|
581
|
+
module_function :exploreSiblings
|
|
582
|
+
|
|
583
|
+
# Look in entries for string that starts with str
|
|
584
|
+
#
|
|
585
|
+
# Returns:
|
|
586
|
+
# - the first match
|
|
587
|
+
# - a list of all matches
|
|
588
|
+
def matchPrefix(entries, str)
|
|
589
|
+
full_name = []
|
|
590
|
+
entries.each(){|ent|
|
|
591
|
+
next if ent !~ /^#{str}/
|
|
592
|
+
full_name << ent
|
|
593
|
+
}
|
|
594
|
+
return full_name[0], full_name
|
|
595
|
+
end
|
|
596
|
+
module_function :matchPrefix
|
|
597
|
+
|
|
598
|
+
# Look in entries for string that contains with str
|
|
599
|
+
#
|
|
600
|
+
# Returns:
|
|
601
|
+
# - the first match
|
|
602
|
+
# - a list of all matches
|
|
603
|
+
def matchExp(entries, str)
|
|
604
|
+
full_name = []
|
|
605
|
+
entries.each(){|ent|
|
|
606
|
+
next if ent !~ /#{str}/
|
|
607
|
+
full_name << ent
|
|
608
|
+
}
|
|
609
|
+
return full_name[0], full_name
|
|
610
|
+
end
|
|
611
|
+
module_function :matchExp
|
|
612
|
+
|
|
613
|
+
# Exception when the provided name matches more than one environment
|
|
614
|
+
class EnvNameErrorException < StandardError
|
|
615
|
+
# Constructor
|
|
616
|
+
#
|
|
617
|
+
# - str: string provided on the command line
|
|
618
|
+
# - matches: array of environment names that matches
|
|
619
|
+
def initialize(str, matches)
|
|
620
|
+
if matches.length == 0 then
|
|
621
|
+
super("'#{str}' match no environment")
|
|
622
|
+
else
|
|
623
|
+
super("'#{str}' match multiple environments: #{matches.join(", ")}")
|
|
624
|
+
end
|
|
625
|
+
end
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
# Exception when no environment name has been provided
|
|
629
|
+
class EnvNoNameErrorException < StandardError
|
|
630
|
+
# Default constructor
|
|
631
|
+
def initialize()
|
|
632
|
+
super("No environment name provided")
|
|
633
|
+
end
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
# Exception when no environment name has been provided
|
|
637
|
+
class EnvNoTypeErrorException < StandardError
|
|
638
|
+
# Default constructor
|
|
639
|
+
def initialize()
|
|
640
|
+
super("No environment type provided")
|
|
641
|
+
end
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
# Exception when no environment name has been provided
|
|
645
|
+
class EnvTypeErrorException < StandardError
|
|
646
|
+
# Constructor
|
|
647
|
+
#
|
|
648
|
+
# - str: string provided on the command line
|
|
649
|
+
def initialize(str)
|
|
650
|
+
super("Environment type '#{str}' is invalid")
|
|
651
|
+
end
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
# Environment name expansion
|
|
655
|
+
#
|
|
656
|
+
# Return the name of an existing environment if 'str' matches at most 1
|
|
657
|
+
# existing environment
|
|
658
|
+
def nameToEnvName(str)
|
|
659
|
+
raise EnvNoNameErrorException if str.to_s == ""
|
|
660
|
+
|
|
661
|
+
return str if isEnv?(str)
|
|
662
|
+
|
|
663
|
+
envs = getEnvs().map(){|x| x.name}
|
|
664
|
+
completeName, matches = matchPrefix(envs, str)
|
|
665
|
+
if matches.length == 0 then
|
|
666
|
+
completeName, matches = matchExp(envs, str)
|
|
667
|
+
end
|
|
668
|
+
|
|
669
|
+
if matches.length != 1 then
|
|
670
|
+
exp = EnvNameErrorException.new(str, matches)
|
|
671
|
+
raise exp
|
|
672
|
+
end
|
|
673
|
+
puts "INFO: Env name '#{str}' matches environment '#{completeName}'"
|
|
674
|
+
return completeName
|
|
675
|
+
end
|
|
676
|
+
module_function :nameToEnvName
|
|
677
|
+
|
|
678
|
+
# Serialize an object to be returns to a calling RPC process through logs
|
|
679
|
+
#
|
|
680
|
+
# Returns a string of the serialized object
|
|
681
|
+
def serialize(str)
|
|
682
|
+
return ":B64_OBJ:" + Base64.encode64(str.to_yaml()).gsub("\n", '') + ":/B64_OBJ:"
|
|
683
|
+
end
|
|
684
|
+
module_function :serialize
|
|
685
|
+
|
|
686
|
+
#Regexp to extract B64 Objects encoded in RPC result
|
|
687
|
+
B64_OBJ_REGXP = /:B64_OBJ:([A-Za-z0-9+\/=]*):\/B64_OBJ:/
|
|
688
|
+
|
|
689
|
+
# Returns an array with all the objects encoded in Base64 within the provided string
|
|
690
|
+
def deserialize(str)
|
|
691
|
+
return str.scan(B64_OBJ_REGXP).map(){|x|
|
|
692
|
+
YAMLLoad(Base64.decode64(x[0].gsub(B64_OBJ_REGXP, '\1')))
|
|
693
|
+
}
|
|
694
|
+
end
|
|
695
|
+
module_function :deserialize
|
|
696
|
+
|
|
697
|
+
# Run a remote Wenv action 'action' with option_str as options.
|
|
698
|
+
#
|
|
699
|
+
# host_str format is [user@]host[:/path/to/wenv]
|
|
700
|
+
#
|
|
701
|
+
# Returns an (array of returned RPC objects, logs without RPC)
|
|
702
|
+
def remoteRun(host_str, action, option_str)
|
|
703
|
+
args=host_str.split(":")
|
|
704
|
+
host=args[0]
|
|
705
|
+
path=""
|
|
706
|
+
path=args[1] + "/" if args.length == 2
|
|
707
|
+
ret = runCmd("ssh -t -t -o StrictHostKeyChecking=no "+
|
|
708
|
+
"#{host} #{path}wenv #{action} #{option_str}", !VERBOSE)
|
|
709
|
+
return deserialize(ret), ret.gsub(B64_OBJ_REGXP, "")
|
|
710
|
+
end
|
|
711
|
+
module_function :remoteRun
|
|
712
|
+
|
|
713
|
+
# Convert a string from CLI to an env Class
|
|
714
|
+
#
|
|
715
|
+
# String is normalement (lower first char) and converted to a label then matched against
|
|
716
|
+
# ENV_TYPE of each env class
|
|
717
|
+
def stringToEnvClass(type)
|
|
718
|
+
normalized_typename = type.to_s.slice(0,1).downcase + type.to_s.slice(1..-1)
|
|
719
|
+
raise EnvTypeErrorException.new(type) if ! isValidType?(type)
|
|
720
|
+
|
|
721
|
+
# Create a new environment or raise an exception if parameters are invalid
|
|
722
|
+
env = nil
|
|
723
|
+
envClass = symbolToClass(normalized_typename)
|
|
724
|
+
raise("Ooops. Failed to generate envClass. Contact support !") if envClass == nil
|
|
725
|
+
return envClass
|
|
726
|
+
end
|
|
727
|
+
module_function :stringToEnvClass
|
|
728
|
+
|
|
729
|
+
# Return a list of all the packages (including internal, temporary, extras)
|
|
730
|
+
# listed in an env Class
|
|
731
|
+
def listAllPackages(objClass)
|
|
732
|
+
getPackages(objClass).values.inject([]){|p, x|
|
|
733
|
+
p + x.values.inject([]){|q, c|
|
|
734
|
+
q+c.map(){|d| d.to_s}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
end
|
|
738
|
+
module_function :listAllPackages
|
|
739
|
+
|
|
740
|
+
# Return a list of all the packages (including internal, temporary, extras)
|
|
741
|
+
# listed in an env Class and its siblings
|
|
742
|
+
def listAllPackagesWithSiblings(objClass)
|
|
743
|
+
return exploreSiblings(objClass).inject([]) { |r, sibling |
|
|
744
|
+
r + listAllPackages(sibling)
|
|
745
|
+
}.uniq
|
|
746
|
+
end
|
|
747
|
+
module_function :listAllPackagesWithSiblings
|
|
748
|
+
end
|
|
749
|
+
|