1 | """ |
---|
2 | InstallFromWorkspace.cobra |
---|
3 | |
---|
4 | This program installs Cobra onto your system out of the workspace. It's a great |
---|
5 | convenience for users who only grab the workspace to get the very latest |
---|
6 | version of Cobra (e.g., they are not developing on the compiler). But even for |
---|
7 | developers, it's convenient to "snapshot" the compiler for your system when |
---|
8 | desired. |
---|
9 | |
---|
10 | Normally the compiler and libraries to be installed are compiled with -turbo. |
---|
11 | However, you can pass an argument to this program such as -debug which will |
---|
12 | replace -turbo. This is useful for troubleshooting. |
---|
13 | |
---|
14 | Why not a .bat file? Won't run on Mac, Linux, etc. |
---|
15 | |
---|
16 | Why not a bash script? Won't run on Windows-sans-cygwin. |
---|
17 | |
---|
18 | Also, as a .NET program this installer has easy access to the GAC and any other |
---|
19 | .NET resources. Furthermore, as a Cobra programmer, any Cobra user could |
---|
20 | potentially hack on it. |
---|
21 | |
---|
22 | |
---|
23 | TO RUN |
---|
24 | |
---|
25 | On Windows |
---|
26 | |
---|
27 | Update, if desired: |
---|
28 | > cd \path\to\Workspace |
---|
29 | > svn up |
---|
30 | |
---|
31 | Get into the Source: |
---|
32 | > cd Source |
---|
33 | |
---|
34 | Use the batch file: |
---|
35 | > install-from-workspace |
---|
36 | |
---|
37 | On Mac, Linux, etc. |
---|
38 | |
---|
39 | Update, if desired: |
---|
40 | $ cd /path/to/Workspace |
---|
41 | $ svn up |
---|
42 | |
---|
43 | Get into the Source: |
---|
44 | $ cd Source |
---|
45 | |
---|
46 | Use the script: |
---|
47 | $ sudo ./install-from-workspace |
---|
48 | |
---|
49 | |
---|
50 | The installer prints "Success!" at the end, if successful. |
---|
51 | Otherwise you will see an error message. |
---|
52 | |
---|
53 | It's safe to run the installer more than once. |
---|
54 | |
---|
55 | The installer does not change any workspace files that are under source code control. |
---|
56 | |
---|
57 | To test the installation, try invoking Cobra from *outside* the workspace. |
---|
58 | |
---|
59 | |
---|
60 | ASSUMPTIONS |
---|
61 | |
---|
62 | * Your system meets the requirements for Novell Mono 2.0 or .NET 2.0 |
---|
63 | http://msdn.microsoft.com/en-us/library/ms229070.aspx |
---|
64 | |
---|
65 | * This program is run in the Workspace\Source directory. |
---|
66 | |
---|
67 | * This program is run by Snapshot\cobra.exe. *NOT* .\cobra.exe |
---|
68 | |
---|
69 | * The current Cobra compiler in Source\ will report a -version equal to the |
---|
70 | last released version plus optional additional text. If the last release |
---|
71 | was "0.8.0" then the new release should be "0.8.0 post". |
---|
72 | |
---|
73 | * The current Cobra compiler in Source\ will have three components to its |
---|
74 | base version *number*. Form: x.y.z Example: 0.8.0 |
---|
75 | |
---|
76 | |
---|
77 | TODO |
---|
78 | |
---|
79 | [ ] Create an install log |
---|
80 | |
---|
81 | [ ] Various "TODO" items in the source itself |
---|
82 | |
---|
83 | """ |
---|
84 | |
---|
85 | use System.Diagnostics |
---|
86 | use System.Reflection |
---|
87 | use System.Text.RegularExpressions |
---|
88 | |
---|
89 | # for GAC installation |
---|
90 | use System.EnterpriseServices |
---|
91 | use System.EnterpriseServices.Internal |
---|
92 | |
---|
93 | |
---|
94 | class InstallFromWorkspace |
---|
95 | |
---|
96 | var installDirectories = [r'C:\Cobra', '/usr/local/cobra'] |
---|
97 | |
---|
98 | var configFileName = 'install-directory.text' |
---|
99 | |
---|
100 | def main is shared |
---|
101 | InstallFromWorkspace().run |
---|
102 | |
---|
103 | var _lastCommand as String? |
---|
104 | |
---|
105 | var _snapshotCompilerPath as String? |
---|
106 | var _gacutil as String? |
---|
107 | var _baseVersion as String? # ex: '0.8.0-post', '0.8.0-post-2009-03-01' |
---|
108 | var _targetDir as String? # ex: 'C:\Cobra', '/usr/local/cobra' |
---|
109 | var _versionDir as String? # ex: 'C:\Cobra\Cobra-0.8.0-post', 'C:\Cobra\Cobra-0.8.0-post-2009-03-01', '/usr/local/cobra/Cobra-0.8.1-post' |
---|
110 | var _cobraCommandPath as String? # ex: 'C:\Cobra\bin\cobra.bat', '/usr/local/cobra/bin/cobra' |
---|
111 | |
---|
112 | |
---|
113 | def run |
---|
114 | print |
---|
115 | print 'The Cobra Programming Language' |
---|
116 | print 'Install From Workspace' |
---|
117 | print |
---|
118 | print 'Working...' |
---|
119 | print |
---|
120 | .verifyInstallDirectory |
---|
121 | .verifyInWorkspace |
---|
122 | .verifyVirtualMachineVersion |
---|
123 | .locateSnapshotCompiler |
---|
124 | # .locateGacUtil |
---|
125 | .buildCobraCompiler |
---|
126 | .getBaseVersion |
---|
127 | .buildCobraLibrary |
---|
128 | .verifyNewlyBuiltCobra |
---|
129 | .installCobraLibraryToGAC |
---|
130 | .copyFilesToInstallDirectory |
---|
131 | .verifyNewlyInstalledCobra |
---|
132 | .cleanUpWorkspace |
---|
133 | .installInPath |
---|
134 | print |
---|
135 | print 'Success!' |
---|
136 | |
---|
137 | |
---|
138 | ## Self utils |
---|
139 | |
---|
140 | get compileFlags as String |
---|
141 | args = CobraCore.commandLineArgs |
---|
142 | if args.count > 1, return args[1] # TODO: should be a join of args[1:] |
---|
143 | else, return '-turbo' |
---|
144 | |
---|
145 | get isRunningOnUnix as bool |
---|
146 | """ |
---|
147 | Returns true if the current process is running on Unix/Posix/Linux/BSD/etc. |
---|
148 | """ |
---|
149 | platform = Environment.osVersion.platform to int |
---|
150 | return platform in [4, 128] # http://www.mono-project.com/FAQ:_Technical |
---|
151 | |
---|
152 | get lastCommand from var |
---|
153 | |
---|
154 | get slash as char |
---|
155 | return Path.directorySeparatorChar |
---|
156 | |
---|
157 | def error(msg) |
---|
158 | print '** ERROR:', msg |
---|
159 | Environment.exit(1) |
---|
160 | print 'Exiting from error.' |
---|
161 | |
---|
162 | def warning(msg) |
---|
163 | print '** WARING:', msg |
---|
164 | |
---|
165 | |
---|
166 | ## File system |
---|
167 | |
---|
168 | def copyContents(source as String, target as String) |
---|
169 | print 'copy from:', source |
---|
170 | print ' to:', target |
---|
171 | .copyContents(DirectoryInfo(source), DirectoryInfo(target)) |
---|
172 | |
---|
173 | def copyContents(source as DirectoryInfo, target as DirectoryInfo) |
---|
174 | if not target.exists, target.create |
---|
175 | for sourceFile in source.getFiles |
---|
176 | sourceFile.copyTo(Path.combine(target.fullName, sourceFile.name), true) |
---|
177 | for sourceSubDir in source.getDirectories |
---|
178 | targetSubDir = target.createSubdirectory(sourceSubDir.name) |
---|
179 | .copyContents(sourceSubDir, targetSubDir) |
---|
180 | |
---|
181 | def deleteDir(dir as String) |
---|
182 | if Directory.exists(dir) |
---|
183 | print 'del dir :', dir |
---|
184 | spacer = ' ' |
---|
185 | _unReadOnly(dir) |
---|
186 | numAttempts = 3 |
---|
187 | for attempt in 1 : numAttempts + 1 |
---|
188 | try |
---|
189 | Directory.delete(dir, true) # true = recursive |
---|
190 | catch IOException |
---|
191 | # sometimes "The directory is not empty." occurs |
---|
192 | if attempt == numAttempts, throw |
---|
193 | print spacer, 'Having trouble deleting directory. Try again in [attempt] seconds.' |
---|
194 | System.Threading.Thread.sleep(attempt*1_000) |
---|
195 | if not Directory.exists(dir) # and sometimes it goes away! |
---|
196 | print spacer, 'Directory is gone.' |
---|
197 | if not Directory.exists(dir), break |
---|
198 | |
---|
199 | def _unReadOnly(dirName as String) |
---|
200 | _unReadOnly(DirectoryInfo(dirName)) |
---|
201 | |
---|
202 | def _unReadOnly(dir as DirectoryInfo) |
---|
203 | # print 'checking -', dir |
---|
204 | for file in dir.getFiles |
---|
205 | if sharp'file.Attributes & System.IO.FileAttributes.ReadOnly' |
---|
206 | # print 'changing -', file |
---|
207 | file.attributes = sharp'file.Attributes & ~System.IO.FileAttributes.ReadOnly' |
---|
208 | # file.attributes = file.attributes & ~FileAttributes.ReadOnly |
---|
209 | for subDir in dir.getDirectories |
---|
210 | _unReadOnly(subDir) |
---|
211 | |
---|
212 | def findAndDeleteDir(baseDir as String, findDir as String) |
---|
213 | .findAndDeleteDir(DirectoryInfo(baseDir), findDir) |
---|
214 | |
---|
215 | def findAndDeleteDir(baseDir as DirectoryInfo, findDir as String) |
---|
216 | for sourceSubDir in baseDir.getDirectories |
---|
217 | if sourceSubDir.name == findDir |
---|
218 | .deleteDir(sourceSubDir.fullName) |
---|
219 | else |
---|
220 | .findAndDeleteDir(sourceSubDir, findDir) |
---|
221 | |
---|
222 | def requireDir(dir as String) |
---|
223 | if Directory.exists(dir) |
---|
224 | print 'found dir:', dir |
---|
225 | else |
---|
226 | print 'make dir :', dir |
---|
227 | try |
---|
228 | Directory.createDirectory(dir) |
---|
229 | catch ex as SystemException |
---|
230 | .error('Unable to create installation directory.\n[ex.message]\nRun as admin, or put a correct install path into a file called "[.configFileName]".') |
---|
231 | |
---|
232 | def startStage(description as String) |
---|
233 | print '====', description |
---|
234 | print |
---|
235 | # this installer relies on there being no directory changes |
---|
236 | assert Environment.currentDirectory.endsWith('Source') |
---|
237 | |
---|
238 | |
---|
239 | ## Running external commands |
---|
240 | |
---|
241 | def runCommand(command as String, args as String) as String |
---|
242 | return .runCommand(command, args, true) |
---|
243 | |
---|
244 | def runCommand(command as String, args as String, displayOutput as bool) as String |
---|
245 | process as Process? |
---|
246 | output = .runCommand(command, args, out process, displayOutput) |
---|
247 | if process.exitCode, .error('Exit code from above command: [process.exitCode]') |
---|
248 | return output |
---|
249 | |
---|
250 | def runCommand(command as String, args as String, process as out Process?) as String |
---|
251 | return .runCommand(command, args, out process, true) |
---|
252 | |
---|
253 | def runCommand(command as String, args as String, process as out Process?, displayOutput as bool) as String |
---|
254 | """ |
---|
255 | Runs the given external command with the given args. |
---|
256 | Sets the process to the instance of Process created for this purpose. |
---|
257 | Returns the output, which is also displayed if displayOutput is true. |
---|
258 | Does not check process.exitCode. |
---|
259 | """ |
---|
260 | print 'run: [command] [args]' |
---|
261 | _lastCommand = command + ' ' + args |
---|
262 | p = Process() |
---|
263 | p.startInfo.fileName = command |
---|
264 | p.startInfo.arguments = args |
---|
265 | output = CobraCore.runAndCaptureAllOutput(p).trim |
---|
266 | process = p |
---|
267 | if displayOutput and output <> '' |
---|
268 | for line in output.replace('\r', '').split(c'\n') |
---|
269 | print ' : [line]' |
---|
270 | print |
---|
271 | return output |
---|
272 | |
---|
273 | def runSnapshotCobra(args as String) as String |
---|
274 | """ |
---|
275 | Runs the Cobra compiler. |
---|
276 | Prints the output and returns it. |
---|
277 | If Cobra gives an error, calls .error. |
---|
278 | """ |
---|
279 | process as Process? |
---|
280 | output = .runSnapshotCobra(args, out process) |
---|
281 | if process.exitCode, .error('Exit code from running SnapshotCobra: [process.exitCode]') |
---|
282 | return output |
---|
283 | |
---|
284 | def runSnapshotCobra(args as String, process as out Process?) as String |
---|
285 | """ |
---|
286 | Runs the Cobra compiler. |
---|
287 | Creates and "returns" the Process instance via the `process` argument. |
---|
288 | Prints the output and returns it. |
---|
289 | This does not exit on any errors. Check the process yourself. |
---|
290 | """ |
---|
291 | return .runCommand(_snapshotCompilerPath to !, args, out process) |
---|
292 | |
---|
293 | def runSourceCobra(args as String) as String |
---|
294 | process as Process? |
---|
295 | output = .runSourceCobra(args, out process) |
---|
296 | if process.exitCode, .error('Exit code from running Source Cobra: [process.exitCode]') |
---|
297 | return output |
---|
298 | |
---|
299 | def runSourceCobra(args as String, process as out Process?) as String |
---|
300 | return .runCommand('cobra.exe', args, out process) |
---|
301 | |
---|
302 | |
---|
303 | ## Stages |
---|
304 | |
---|
305 | def verifyInstallDirectory |
---|
306 | .startStage('Verify installation directory') |
---|
307 | default = if(.isRunningOnUnix, .installDirectories[1], .installDirectories[0]) |
---|
308 | if File.exists(.configFileName) |
---|
309 | # get install directory from first line of the file |
---|
310 | useDir = File.openText(.configFileName).readLine |
---|
311 | if useDir and useDir.trim.length, default = useDir.trim |
---|
312 | # TODO: prompt the user for the location |
---|
313 | .requireDir(default) |
---|
314 | _targetDir = default |
---|
315 | print |
---|
316 | |
---|
317 | def verifyInWorkspace |
---|
318 | .startStage('Verify running in workspace') |
---|
319 | msg = 'The current directory does not appear to be a workspace. This program is for installing from the workspace.' |
---|
320 | if not File.exists('Compiler.cobra'), .error(msg) |
---|
321 | if not Directory.exists('Snapshot'), .error(msg) |
---|
322 | print 'Verified.' |
---|
323 | print |
---|
324 | |
---|
325 | def verifyVirtualMachineVersion |
---|
326 | if CobraCore.isRunningOnMono |
---|
327 | .startStage('Verify Novell Mono version') |
---|
328 | if CobraCore.isRunningOnMono |
---|
329 | minMonoVersion = '2.0' |
---|
330 | vers = CobraCore.monoVersionString |
---|
331 | if vers is nil or vers.trim == '' |
---|
332 | .error('Cannot determine Mono version. Please install Mono [minMonoVersion] or higher.') |
---|
333 | else |
---|
334 | print 'Mono Version', vers |
---|
335 | parts = vers.split(c'.') |
---|
336 | if parts and parts[0] >= '2' |
---|
337 | print 'Verified >= [minMonoVersion]' |
---|
338 | print |
---|
339 | else |
---|
340 | .error('Mono version must be [minMonoVersion] or higher.') |
---|
341 | |
---|
342 | def locateSnapshotCompiler |
---|
343 | .startStage('Locate and test Cobra Snapshot compiler') |
---|
344 | _snapshotCompilerPath = 'Snapshot[.slash]cobra.exe' |
---|
345 | if not File.exists(_snapshotCompilerPath) |
---|
346 | .error('Cannot locate [_snapshotCompilerPath].') |
---|
347 | # Not needed; clutters the output; tends to obscure when the Snapshot is being used; |
---|
348 | # _snapshotCompilerPath = Path.getFullPath(_snapshotCompilerPath) |
---|
349 | output = .runSnapshotCobra('-about') |
---|
350 | assert 'The Cobra Programming Language' in output |
---|
351 | assert 'Copyright' in output |
---|
352 | assert 'Usage' in output |
---|
353 | |
---|
354 | def locateGacUtil(startStage as bool) |
---|
355 | if startStage, .startStage('Locate gacutil.exe') |
---|
356 | slash = .slash |
---|
357 | gacutil = 'gacutil' |
---|
358 | p = Process() |
---|
359 | p.startInfo.fileName = gacutil |
---|
360 | p.startInfo.arguments = '-silent' |
---|
361 | try |
---|
362 | CobraCore.runAndCaptureAllOutput(p) |
---|
363 | found = true |
---|
364 | print 'found in system PATH' |
---|
365 | catch FileNotFoundException |
---|
366 | pass |
---|
367 | catch ComponentModel.Win32Exception |
---|
368 | pass |
---|
369 | |
---|
370 | if not found |
---|
371 | # try to find the gacutil |
---|
372 | print 'Searching for gacutil...' |
---|
373 | gacutil = 'gacutil.exe' |
---|
374 | |
---|
375 | dirs = [ |
---|
376 | r'Microsoft.NET\SDK\v2.0\bin', # VS 2005 / SDK .NET 2.0 |
---|
377 | r'Microsoft SDKs\Windows\v6.0A\bin', # VS 2008 |
---|
378 | r'Microsoft Visual Studio 8\SDK\v2.0\Bin', |
---|
379 | ] |
---|
380 | |
---|
381 | # search %ProgramFiles% (which can differ internationally) |
---|
382 | programFilesDir = Environment.getFolderPath(Environment.SpecialFolder.ProgramFiles) |
---|
383 | for dir in dirs |
---|
384 | path = '[programFilesDir][slash][dir][slash][gacutil]' |
---|
385 | print 'checking:', path |
---|
386 | if File.exists(path) |
---|
387 | print 'found:', path |
---|
388 | gacutil = path |
---|
389 | found = true |
---|
390 | break |
---|
391 | # else, print path |
---|
392 | |
---|
393 | if not found |
---|
394 | for dir in dirs |
---|
395 | # search drives for X:\Program Files\... |
---|
396 | for drive in Directory.getLogicalDrives |
---|
397 | drive = drive[:1] # normalize to just one character |
---|
398 | if drive <= 'B', continue |
---|
399 | path = '[drive]:[slash]Program Files[slash][dir][slash][gacutil]' |
---|
400 | print 'checking:', path |
---|
401 | if File.exists(path) |
---|
402 | print 'found:', path |
---|
403 | gacutil = path |
---|
404 | found = true |
---|
405 | break |
---|
406 | # else, print path |
---|
407 | if found, break |
---|
408 | |
---|
409 | if not found |
---|
410 | .error('Cannot locate a gacutil. Maybe you can try again using the "Visual Studio Command Prompt" or ".NET SDK Command Prompt".') |
---|
411 | |
---|
412 | _gacutil = gacutil |
---|
413 | print |
---|
414 | |
---|
415 | def buildCobraCompiler |
---|
416 | .startStage('Build new Cobra compiler') |
---|
417 | .runSnapshotCobra('-compile [.compileFlags] -ert:yes cobra.cobra -files:files-to-compile.text') |
---|
418 | |
---|
419 | def getBaseVersion |
---|
420 | .startStage('Retrieve Cobra base version number') |
---|
421 | # It's called "base version" because it doesn't include any text after the numbers |
---|
422 | # "0.8.0 post release" --> "0.8.0" |
---|
423 | output = .runSourceCobra('-version') |
---|
424 | re = Regex(r'\d+\.\d+\.\d+') |
---|
425 | reMatch = re.match(output) |
---|
426 | if reMatch.success |
---|
427 | assert reMatch.value |
---|
428 | _baseVersion = reMatch.value |
---|
429 | else |
---|
430 | .error('Could not extract base version number.') |
---|
431 | _baseVersion += '-post' |
---|
432 | # check for an informal release |
---|
433 | parent = Path.getFullPath('..') |
---|
434 | if File.exists('[parent][.slash]InformalRelease.text') |
---|
435 | output = File.readAllText('[parent][.slash]InformalRelease.text') |
---|
436 | re = Regex(r'\d+\-\d+\-\d+') |
---|
437 | reMatch = re.match(output) |
---|
438 | if reMatch.success |
---|
439 | assert reMatch.value |
---|
440 | _baseVersion += '-' + reMatch.value |
---|
441 | else |
---|
442 | .error('Could not extract date from InformalRelease.text') |
---|
443 | print 'base version: [_baseVersion]' |
---|
444 | print |
---|
445 | |
---|
446 | def buildCobraLibrary |
---|
447 | .startStage('Build Cobra standard library') |
---|
448 | # must build the library using the Source cobra.exe, not the Snapshot |
---|
449 | .runSourceCobra('-bsl [.compileFlags] Cobra.Lang[.slash]AssemblyAttrs.cobra -key-file:Cobra.Lang[.slash]Cobra.Lang.snk') |
---|
450 | |
---|
451 | def verifyNewlyBuiltCobra |
---|
452 | .startStage('Verify newly built Cobra compiler') |
---|
453 | .runSourceCobra('-about') |
---|
454 | msg = 'Cannot run hello.cobra with new compiler.' |
---|
455 | output = .runSourceCobra('-ert:no hello') |
---|
456 | if not output.startsWith('Hello'), .error(msg) |
---|
457 | output = .runSourceCobra('-ert:yes hello') |
---|
458 | if not output.startsWith('Hello'), .error(msg) |
---|
459 | output = .runSourceCobra('hello') |
---|
460 | if not output.startsWith('Hello'), .error(msg) |
---|
461 | |
---|
462 | def installCobraLibraryToGAC |
---|
463 | .startStage('Install Cobra standard library to the GAC') |
---|
464 | print 'Invoking Publish.GacInstall...' |
---|
465 | try |
---|
466 | Publish().gacInstall('Cobra.Lang.dll') |
---|
467 | print 'Done.' |
---|
468 | catch NotImplementedException |
---|
469 | print 'Not implemented exception.' |
---|
470 | print 'Will attempt to use gacutil.exe.' |
---|
471 | .locateGacUtil(false) |
---|
472 | .runCommand(_gacutil, '-i Cobra.Lang.dll -f') |
---|
473 | output = .runCommand(_gacutil, '-l Cobra.Lang') |
---|
474 | if 'Cobra.Lang, Version=' not in output |
---|
475 | .error('Cannot see Cobra.Lang in the gacutil output to list it above.') |
---|
476 | # TODO: verify the version number: Cobra.Lang, Version=0.0.1.0 |
---|
477 | print |
---|
478 | |
---|
479 | def copyFilesToInstallDirectory |
---|
480 | require _targetDir is not nil |
---|
481 | .startStage('Copy files to install directory') |
---|
482 | slash = .slash |
---|
483 | targetDir = _targetDir |
---|
484 | |
---|
485 | if targetDir, .requireDir(targetDir) |
---|
486 | if Directory.exists(Path.combine(targetDir, 'Source')) |
---|
487 | print 'The directory "[targetDir]" appears to contain a workspace or snapshot of the' |
---|
488 | print 'Cobra source code, due to containing the subdirectory "Source".' |
---|
489 | print 'Installing to that location can lead to confusion and technical difficulties.' |
---|
490 | print 'Consider clearing out "[targetDir]" and creating a workspace *inside* it called,' |
---|
491 | print 'for example, "Workspace".' |
---|
492 | print |
---|
493 | .error('Cannot install to workspace or workspace snapshot. See message above.') |
---|
494 | |
---|
495 | versionDir = '[targetDir][slash]Cobra-[_baseVersion]' |
---|
496 | .deleteDir(versionDir) |
---|
497 | .requireDir(versionDir) |
---|
498 | _versionDir = versionDir |
---|
499 | |
---|
500 | # TODO: readme file? |
---|
501 | parent = Path.getFullPath('..') |
---|
502 | |
---|
503 | versionOutput = '' |
---|
504 | if File.exists('[parent][slash]InformalRelease.text') |
---|
505 | versionOutput = File.readAllText('[parent][slash]InformalRelease.text') |
---|
506 | else |
---|
507 | # record "svn info" in the installation directory |
---|
508 | svnFailed = 'Cannot find version information, svn command line version not installed or failed.' |
---|
509 | try |
---|
510 | process as Process? |
---|
511 | versionOutput = .runCommand('svn', 'info', out process, false) |
---|
512 | if process.exitCode |
---|
513 | print '"svn info" failed. Check your svn installation.' |
---|
514 | print '[versionOutput]' |
---|
515 | print |
---|
516 | .warning(svnFailed) |
---|
517 | catch ex as SystemException |
---|
518 | # user could be on TortoiseSVN |
---|
519 | print 'svn is not installed or it is not in the PATH. ', ex.message |
---|
520 | .warning(svnFailed) |
---|
521 | if versionOutput <> '' |
---|
522 | fileName = '[versionDir][slash]Version.text' |
---|
523 | print 'writing :', fileName |
---|
524 | File.writeAllText(fileName, versionOutput) |
---|
525 | print |
---|
526 | |
---|
527 | for dir in ['HowTo', 'Reusables', 'Samples', 'Supplements'] |
---|
528 | .copyContents('[parent][slash][dir]', '[versionDir][slash][dir]') |
---|
529 | |
---|
530 | versionBinDir = '[versionDir][slash]bin' |
---|
531 | .requireDir(versionBinDir) |
---|
532 | print 'copy bin: [versionBinDir]' |
---|
533 | binFiles = 'cobra.exe Cobra.Lang.dll Cobra.Sharp.dll styles-cobra-doc.css styles-exception-report.css styles-output-html.css'.split |
---|
534 | for fileName in binFiles |
---|
535 | File.copy(fileName, '[versionBinDir][slash][fileName]') |
---|
536 | |
---|
537 | .copyContents('Cobra.Lang', '[versionBinDir][slash]Cobra.Lang') |
---|
538 | |
---|
539 | # delete _svn or .svn from the installation directory |
---|
540 | .findAndDeleteDir(versionDir, '_svn') |
---|
541 | .findAndDeleteDir(versionDir, '.svn') |
---|
542 | |
---|
543 | # create cobra.bat / cobra for invoking the latest version |
---|
544 | baseBinDir = '[targetDir][slash]bin' |
---|
545 | .requireDir(baseBinDir) |
---|
546 | if .isRunningOnUnix |
---|
547 | _cobraCommandPath = '[baseBinDir][slash]cobra' |
---|
548 | print 'writing :', _cobraCommandPath |
---|
549 | using f = File.createText(_cobraCommandPath) |
---|
550 | f.writeLine('#!/bin/sh') |
---|
551 | f.writeLine('exec mono "[versionDir][slash]bin[slash]cobra.exe" "$@"') |
---|
552 | .runCommand('chmod', "a+x '[_cobraCommandPath]'") |
---|
553 | else |
---|
554 | _cobraCommandPath = '[baseBinDir][slash]cobra.bat' |
---|
555 | print 'writing :', _cobraCommandPath |
---|
556 | using f = File.createText(_cobraCommandPath) |
---|
557 | f.writeLine('@"[versionDir][slash]bin[slash]cobra.exe" %*') |
---|
558 | print |
---|
559 | |
---|
560 | def verifyNewlyInstalledCobra |
---|
561 | .startStage('Verify newly installed Cobra compiler') |
---|
562 | output = .runCommand(_cobraCommandPath, '-about', true) |
---|
563 | if not output.startsWith('The Cobra Programming Language') |
---|
564 | .error('Cannot run the installed Cobra with -about') |
---|
565 | output = .runCommand(_cobraCommandPath, '-ert:yes hello', true) |
---|
566 | if not output.startsWith('Hello') |
---|
567 | .error('Cannot run the installed Cobra on "hello.cobra"') |
---|
568 | |
---|
569 | def cleanUpWorkspace |
---|
570 | .startStage('Clean up workspace') |
---|
571 | .runSnapshotCobra('-compile -debug -ert:yes cobra.cobra -files:files-to-compile.text') |
---|
572 | .runSourceCobra('-bsl -debug') |
---|
573 | |
---|
574 | def installInPath |
---|
575 | .startStage('Install "cobra" into a system path directory') |
---|
576 | commandName = if(.isRunningOnUnix, 'cobra', 'cobra.bat') |
---|
577 | slash = .slash |
---|
578 | paths = (Environment.getEnvironmentVariable('PATH') ? '').split(Path.pathSeparator) |
---|
579 | for commandDir in paths |
---|
580 | if commandDir == '.', continue # skip the 'cobra' in the <workspace>/Source directory |
---|
581 | # print 'checking path:', commandDir |
---|
582 | if commandDir.startsWith('~') |
---|
583 | home = Environment.getEnvironmentVariable('HOME') |
---|
584 | if home, commandDir = home + commandDir[1:] |
---|
585 | commandPath = Path.getFullPath('[commandDir][slash][commandName]') |
---|
586 | if File.exists(commandPath) |
---|
587 | print 'found in PATH:', commandPath |
---|
588 | found = true |
---|
589 | break |
---|
590 | print |
---|
591 | baseBinDir = '[_targetDir][slash]bin' |
---|
592 | if found |
---|
593 | if String.compare(commandPath, '[baseBinDir][slash][commandName]', not .isRunningOnUnix) == 0 |
---|
594 | print 'Your PATH already contains [baseBinDir]' |
---|
595 | print 'so you can invoke "cobra" from any directory.' |
---|
596 | else |
---|
597 | if .newlyCompiledFileIsSymlinkedFromOneFoundOnPath(_cobraCommandPath, commandPath) |
---|
598 | print 'The existing "cobra" in your path is a symbolic' |
---|
599 | print 'link and has not been changed.' |
---|
600 | else |
---|
601 | print 'copy from:', _cobraCommandPath |
---|
602 | print ' to:', commandPath |
---|
603 | File.copy(_cobraCommandPath, commandPath, true) |
---|
604 | print |
---|
605 | print 'The existing "cobra" in your path has been replaced' |
---|
606 | print 'with the new one.' |
---|
607 | else |
---|
608 | # TODO: on unix, create a symlink in /usr/local/bin or /usr/bin if they exist and are in the path |
---|
609 | print 'The Cobra compiler is not in your PATH. To remedy you can:' |
---|
610 | print '1. Add [Path.getDirectoryName(_cobraCommandPath)] to your PATH' |
---|
611 | print '2. Copy [_cobraCommandPath] to any directory in your PATH' |
---|
612 | |
---|
613 | def newlyCompiledFileIsSymlinkedFromOneFoundOnPath(cobraCommandPath, commandPath) as bool |
---|
614 | if .isRunningOnUnix |
---|
615 | monoAssembly = Assembly.load('Mono.Posix, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756') |
---|
616 | unixFileSystemInfo as Type = monoAssembly.getType('Mono.Unix.UnixFileSystemInfo') |
---|
617 | fileInfo as dynamic = .getFileSystemEntry(unixFileSystemInfo, commandPath) # When ticket 208 is fixed delete this |
---|
618 | #fileInfo as dynamic = unixFileSystemInfo.getFileSystemEntry(commandPath) # and uncomment this. |
---|
619 | if fileInfo.isSymbolicLink |
---|
620 | unixSymbolicLinkInfo as Type = monoAssembly.getType('Mono.Unix.UnixSymbolicLinkInfo') |
---|
621 | symbolicLinkInfo as dynamic = Convert.changeType(fileInfo, unixSymbolicLinkInfo) to ! |
---|
622 | if symbolicLinkInfo.contentsPath == _cobraCommandPath |
---|
623 | return true |
---|
624 | return false |
---|
625 | |
---|
626 | # When ticket 208 is fixed delete this. |
---|
627 | def getFileSystemEntry(unixFileSystemInfo as Type, commandPath as String) as dynamic |
---|
628 | return unixFileSystemInfo.invokeMember('GetFileSystemEntry', _ |
---|
629 | BindingFlags(Static, InvokeMethod), _ |
---|
630 | nil, _ |
---|
631 | nil, _ |
---|
632 | @[commandPath]) to ! |
---|
633 | |
---|