| 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 | NOTES |
|---|
| 61 | |
|---|
| 62 | In some special cases, users have required that Cobra.Lang.dll not be |
|---|
| 63 | installed to the GAC. There is an option for this called -skip-std-lib. |
|---|
| 64 | Any other command line options are passed to the Cobra snapshot compiler |
|---|
| 65 | when invoked to compile the compiler source code. If no options are |
|---|
| 66 | specified, -turbo is the default. |
|---|
| 67 | |
|---|
| 68 | |
|---|
| 69 | ASSUMPTIONS |
|---|
| 70 | |
|---|
| 71 | * Your system meets the requirements for Novell Mono 2.6 or .NET 2.0 |
|---|
| 72 | http://msdn.microsoft.com/en-us/library/ms229070.aspx |
|---|
| 73 | |
|---|
| 74 | * This program is run in the Workspace\Source directory. |
|---|
| 75 | |
|---|
| 76 | * This program is run by Snapshot\cobra.exe. *NOT* .\cobra.exe |
|---|
| 77 | |
|---|
| 78 | * The current Cobra compiler in Source\ will report a -version equal to the |
|---|
| 79 | last released version plus optional additional text. If the last release |
|---|
| 80 | was "0.8.0" then the new release should be "0.8.0 post". |
|---|
| 81 | |
|---|
| 82 | * The current Cobra compiler in Source\ will have three components to its |
|---|
| 83 | base version *number*. Form: x.y.z Example: 0.8.0 |
|---|
| 84 | |
|---|
| 85 | |
|---|
| 86 | TODO |
|---|
| 87 | |
|---|
| 88 | [ ] Create an install log |
|---|
| 89 | |
|---|
| 90 | [ ] Various "TODO" items in the source itself |
|---|
| 91 | |
|---|
| 92 | """ |
|---|
| 93 | |
|---|
| 94 | use System.Diagnostics |
|---|
| 95 | use System.Reflection |
|---|
| 96 | use System.Security.Principal |
|---|
| 97 | use System.Text.RegularExpressions |
|---|
| 98 | |
|---|
| 99 | # for GAC installation |
|---|
| 100 | use System.EnterpriseServices |
|---|
| 101 | use System.EnterpriseServices.Internal |
|---|
| 102 | |
|---|
| 103 | |
|---|
| 104 | class InstallFromWorkspace |
|---|
| 105 | |
|---|
| 106 | var installDirectories = [r'C:\Cobra', '/usr/local/cobra'] |
|---|
| 107 | |
|---|
| 108 | const configFileName = 'install-directory.text' |
|---|
| 109 | |
|---|
| 110 | var libs = [ |
|---|
| 111 | { |
|---|
| 112 | 'name': 'Cobra.Lang', |
|---|
| 113 | 'flags': '-build-standard-library', |
|---|
| 114 | 'files': 'Cobra.Lang/AssemblyAttrs.cobra', |
|---|
| 115 | }, |
|---|
| 116 | { |
|---|
| 117 | 'name': 'Cobra.Lang.Compiler', |
|---|
| 118 | 'flags': '-c -t:lib -namespace:Cobra.Lang.Compiler -files:files-to-compile.text', |
|---|
| 119 | 'files': 'cobra.cobra', |
|---|
| 120 | }, |
|---|
| 121 | ] |
|---|
| 122 | |
|---|
| 123 | def main is shared |
|---|
| 124 | InstallFromWorkspace().run |
|---|
| 125 | |
|---|
| 126 | var _lastCommand as String? |
|---|
| 127 | |
|---|
| 128 | var _snapshotCompilerPath as String? |
|---|
| 129 | var _gacutil as String? |
|---|
| 130 | var _baseVersion as String? # ex: '0.8.0-post', '0.8.0-post-2009-03-01' |
|---|
| 131 | var _targetDir as String? # ex: 'C:\Cobra', '/usr/local/cobra' |
|---|
| 132 | 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' |
|---|
| 133 | var _cobraCommandPath as String? # ex: 'C:\Cobra\bin\cobra.bat', '/usr/local/cobra/bin/cobra' |
|---|
| 134 | var _args = List<of String>() |
|---|
| 135 | var _skipStdLib = false |
|---|
| 136 | var _willForceDotNet4 = false |
|---|
| 137 | |
|---|
| 138 | def run |
|---|
| 139 | print |
|---|
| 140 | print 'The Cobra Programming Language' |
|---|
| 141 | print 'Install From Workspace' |
|---|
| 142 | print |
|---|
| 143 | print 'Working...' |
|---|
| 144 | print |
|---|
| 145 | .printPlatform |
|---|
| 146 | _args = .parseCommandLineArgs |
|---|
| 147 | .verifyElevatedPermissions |
|---|
| 148 | .verifyInstallDirectory |
|---|
| 149 | .verifyInWorkspace |
|---|
| 150 | .askNet4 |
|---|
| 151 | .verifyVirtualMachineVersion |
|---|
| 152 | .locateSnapshotCompiler |
|---|
| 153 | # .locateGacUtil |
|---|
| 154 | .buildCobraCompiler |
|---|
| 155 | .getBaseVersion |
|---|
| 156 | if not _skipStdLib |
|---|
| 157 | for lib in .libs |
|---|
| 158 | # keys: name, flags |
|---|
| 159 | libName = lib['name'] |
|---|
| 160 | assert not libName.endsWith('.dll') |
|---|
| 161 | .installLibrary(libName, lib['flags'], lib['files'].replace('/', .slash.toString)) |
|---|
| 162 | .verifyNewlyBuiltCobra |
|---|
| 163 | .copyFilesToInstallDirectory |
|---|
| 164 | .verifyNewlyInstalledCobra |
|---|
| 165 | .cleanUpWorkspace |
|---|
| 166 | .installInPath |
|---|
| 167 | print |
|---|
| 168 | print 'Visit http://cobra-language.com/ for discussion, wiki, samples, irc and more.' |
|---|
| 169 | print |
|---|
| 170 | print 'Success!' |
|---|
| 171 | |
|---|
| 172 | |
|---|
| 173 | ## Self utils |
|---|
| 174 | |
|---|
| 175 | get compileFlags as String |
|---|
| 176 | if _args.count > 0, return _args.join(' ') |
|---|
| 177 | else, return '-turbo' |
|---|
| 178 | |
|---|
| 179 | def isRunningOnCLR2 as bool |
|---|
| 180 | ver = Assembly.getAssembly(Object).imageRuntimeVersion |
|---|
| 181 | return ver.startsWith('v2.') or ver.startsWith('2.') |
|---|
| 182 | |
|---|
| 183 | def isRunningOnWindows as bool |
|---|
| 184 | return not .isRunningOnUnix |
|---|
| 185 | |
|---|
| 186 | def isRunningOnUnix as bool |
|---|
| 187 | """ |
|---|
| 188 | Returns true if the current process is running on Unix/Posix/Linux/BSD/etc. |
|---|
| 189 | """ |
|---|
| 190 | return CobraCore.isRunningOnUnix |
|---|
| 191 | |
|---|
| 192 | get lastCommand from var |
|---|
| 193 | |
|---|
| 194 | get slash as char |
|---|
| 195 | return Path.directorySeparatorChar |
|---|
| 196 | |
|---|
| 197 | def parseCommandLineArgs as List<of String> |
|---|
| 198 | args = CobraCore.commandLineArgs |
|---|
| 199 | args = args[1:] |
|---|
| 200 | |
|---|
| 201 | i = args.indexOf('-skip-std-lib') |
|---|
| 202 | if i > -1 |
|---|
| 203 | args.removeAt(i) |
|---|
| 204 | _skipStdLib = true |
|---|
| 205 | |
|---|
| 206 | i = args.indexOf('-net4') |
|---|
| 207 | if i == -1, i = args.indexOf('-dotnet4') |
|---|
| 208 | if i > -1 |
|---|
| 209 | args.removeAt(i) |
|---|
| 210 | _willForceDotNet4 = true |
|---|
| 211 | |
|---|
| 212 | return args |
|---|
| 213 | |
|---|
| 214 | def setUpCLR4(args as List<of String>) |
|---|
| 215 | # locate the external C# .NET 4 compiler |
|---|
| 216 | if CobraCore.isRunningOnMono |
|---|
| 217 | .setUpCLR4InMono(args) |
|---|
| 218 | else if .isRunningOnUnix |
|---|
| 219 | # does not compute. hmmm maybe DotGNU? |
|---|
| 220 | .error('Running on UNIX, but not running Mono. Cannot support -net4.') |
|---|
| 221 | else |
|---|
| 222 | .setUpCLR4InDotNet4(args) |
|---|
| 223 | args.add('-turbo') |
|---|
| 224 | |
|---|
| 225 | def setUpCLR4InMono(args as List<of String>) |
|---|
| 226 | # look for dmcs - the Mono C# .NET 4 compiler |
|---|
| 227 | found = false |
|---|
| 228 | for path in Environment.getEnvironmentVariable('PATH').split(c':') |
|---|
| 229 | dmcs = Path.combine(path, 'dmcs') |
|---|
| 230 | if File.exists(dmcs) |
|---|
| 231 | found = true |
|---|
| 232 | break |
|---|
| 233 | if not found |
|---|
| 234 | .error('Cannot find the Mono dmcs compiler required by -net4. Make sure you have Mono 2.10+ installed and that dmcs is on your path.') |
|---|
| 235 | args.add('-native-compiler:' + dmcs) |
|---|
| 236 | |
|---|
| 237 | def setUpCLR4InDotNet4(args as List<of String>) |
|---|
| 238 | # should be on Windows and Microsoft.NET at this point |
|---|
| 239 | # look for the Microsoft .NET 4.0 compiler |
|---|
| 240 | # Unfortunately, it's mere existance can be a red herring-- |
|---|
| 241 | # a Windows 7 Ult 32-bit user for example, will have this file, but will still need to |
|---|
| 242 | # install either .NET 4.0 or one of the Microsoft Visual 2010 products. |
|---|
| 243 | |
|---|
| 244 | # the 'Windows' enum is only in .NET 4: |
|---|
| 245 | # windowsPath = Environment.getFolderPath(Environment.SpecialFolder.Windows) # typically C:\Windows |
|---|
| 246 | |
|---|
| 247 | for envVarName in ['windir', 'WINDIR', 'systemroot', 'SYSTEMROOT'] |
|---|
| 248 | windowsPath = Environment.getEnvironmentVariable(envVarName) |
|---|
| 249 | if windowsPath and windowsPath <> '' |
|---|
| 250 | break |
|---|
| 251 | if windowsPath is nil or windowsPath == '' |
|---|
| 252 | .error('Cannot locate the Windows system directory required by -net4.') |
|---|
| 253 | csc = Path.combine(windowsPath, r'Microsoft.NET\Framework\v4.0.30319\csc.exe') |
|---|
| 254 | if not File.exists(csc) |
|---|
| 255 | .error('Cannot find the Microsoft csc compiler required by -net4. Try installing MS .NET 4.0, or the 4.0+SDK or one of the Visual 2010 products (the Express ones are free).') |
|---|
| 256 | args.add('-native-compiler:' + csc) |
|---|
| 257 | |
|---|
| 258 | def error(msg) |
|---|
| 259 | print '** ERROR:', msg |
|---|
| 260 | print 'Need help with the above error?' |
|---|
| 261 | if .isRunningOnUnix |
|---|
| 262 | print ' * Make sure you ran with sudo or as root.' |
|---|
| 263 | print ' * Mono 2.6.x or Mono 2.10.x or higher are recommended.' |
|---|
| 264 | else |
|---|
| 265 | print ' * Make sure you ran as a Windows Administrator.' |
|---|
| 266 | print ' * Install .NET or a Visual Studio product if you have not before.' |
|---|
| 267 | print ' * Review http://cobra-language.com/troubleshooting' |
|---|
| 268 | print ' * Ask at http://cobra-language.com/discuss' |
|---|
| 269 | print ' * Ask at http://cobra-language.com/irc' |
|---|
| 270 | Environment.exit(1) |
|---|
| 271 | print 'Exiting from error.' |
|---|
| 272 | |
|---|
| 273 | def warning(msg) |
|---|
| 274 | print '** WARNING:', msg |
|---|
| 275 | |
|---|
| 276 | def isAdmin as bool |
|---|
| 277 | wi = WindowsIdentity.getCurrent |
|---|
| 278 | wp = WindowsPrincipal(wi) |
|---|
| 279 | return wp.isInRole(WindowsBuiltInRole.Administrator) or wi.token == IntPtr.zero |
|---|
| 280 | |
|---|
| 281 | |
|---|
| 282 | ## File system |
|---|
| 283 | |
|---|
| 284 | def copyContents(source as String, target as String) |
|---|
| 285 | print 'copy from:', source |
|---|
| 286 | print ' to:', target |
|---|
| 287 | .copyContents(DirectoryInfo(source), DirectoryInfo(target)) |
|---|
| 288 | |
|---|
| 289 | def copyContents(source as DirectoryInfo, target as DirectoryInfo) |
|---|
| 290 | if not target.exists, target.create |
|---|
| 291 | for sourceFile in source.getFiles |
|---|
| 292 | sourceFile.copyTo(Path.combine(target.fullName, sourceFile.name), true) |
|---|
| 293 | for sourceSubDir in source.getDirectories |
|---|
| 294 | targetSubDir = target.createSubdirectory(sourceSubDir.name) |
|---|
| 295 | .copyContents(sourceSubDir, targetSubDir) |
|---|
| 296 | |
|---|
| 297 | def deleteDir(dir as String) |
|---|
| 298 | if Directory.exists(dir) |
|---|
| 299 | print 'del dir :', dir |
|---|
| 300 | spacer = ' ' |
|---|
| 301 | _unReadOnly(dir) |
|---|
| 302 | numAttempts = 3 |
|---|
| 303 | for attempt in 1 : numAttempts + 1 |
|---|
| 304 | try |
|---|
| 305 | Directory.delete(dir, true) # true = recursive |
|---|
| 306 | catch IOException |
|---|
| 307 | # sometimes "The directory is not empty." occurs |
|---|
| 308 | if attempt == numAttempts, throw |
|---|
| 309 | print spacer, 'Having trouble deleting directory. Try again in [attempt] seconds.' |
|---|
| 310 | System.Threading.Thread.sleep(attempt*1_000) |
|---|
| 311 | if not Directory.exists(dir) # and sometimes it goes away! |
|---|
| 312 | print spacer, 'Directory is gone.' |
|---|
| 313 | if not Directory.exists(dir), break |
|---|
| 314 | |
|---|
| 315 | def _unReadOnly(dirName as String) |
|---|
| 316 | _unReadOnly(DirectoryInfo(dirName)) |
|---|
| 317 | |
|---|
| 318 | def _unReadOnly(dir as DirectoryInfo) |
|---|
| 319 | # print 'checking -', dir |
|---|
| 320 | for file in dir.getFiles |
|---|
| 321 | if sharp'file.Attributes & System.IO.FileAttributes.ReadOnly' |
|---|
| 322 | # print 'changing -', file |
|---|
| 323 | file.attributes = sharp'file.Attributes & ~System.IO.FileAttributes.ReadOnly' |
|---|
| 324 | # file.attributes = file.attributes & ~FileAttributes.ReadOnly |
|---|
| 325 | for subDir in dir.getDirectories |
|---|
| 326 | _unReadOnly(subDir) |
|---|
| 327 | |
|---|
| 328 | def findAndDeleteDir(baseDir as String, findDir as String) |
|---|
| 329 | .findAndDeleteDir(DirectoryInfo(baseDir), findDir) |
|---|
| 330 | |
|---|
| 331 | def findAndDeleteDir(baseDir as DirectoryInfo, findDir as String) |
|---|
| 332 | for sourceSubDir in baseDir.getDirectories |
|---|
| 333 | if sourceSubDir.name == findDir |
|---|
| 334 | .deleteDir(sourceSubDir.fullName) |
|---|
| 335 | else |
|---|
| 336 | .findAndDeleteDir(sourceSubDir, findDir) |
|---|
| 337 | |
|---|
| 338 | def requireDir(dir as String) |
|---|
| 339 | if Directory.exists(dir) |
|---|
| 340 | print 'found dir:', dir |
|---|
| 341 | else |
|---|
| 342 | print 'make dir :', dir |
|---|
| 343 | try |
|---|
| 344 | Directory.createDirectory(dir) |
|---|
| 345 | catch ex as SystemException |
|---|
| 346 | .error('Unable to create installation directory.\n[ex.message]\nRun as admin, or put a correct install path into a file called "[.configFileName]".') |
|---|
| 347 | |
|---|
| 348 | def startStage(description as String) |
|---|
| 349 | print '====', description |
|---|
| 350 | print |
|---|
| 351 | # this installer relies on there being no directory changes |
|---|
| 352 | assert Environment.currentDirectory.endsWith('Source') |
|---|
| 353 | |
|---|
| 354 | |
|---|
| 355 | ## Running external commands |
|---|
| 356 | |
|---|
| 357 | def runCommand(command as String, args as String) as String |
|---|
| 358 | return .runCommand(command, args, true) |
|---|
| 359 | |
|---|
| 360 | def runCommand(command as String, args as String, displayOutput as bool) as String |
|---|
| 361 | process as Process? |
|---|
| 362 | output = .runCommand(command, args, out process, displayOutput) |
|---|
| 363 | if process.exitCode, .error('Exit code from above command: [process.exitCode]') |
|---|
| 364 | return output |
|---|
| 365 | |
|---|
| 366 | def runCommand(command as String, args as String, process as out Process?) as String |
|---|
| 367 | return .runCommand(command, args, out process, true) |
|---|
| 368 | |
|---|
| 369 | def runCommand(command as String, args as String, process as out Process?, displayOutput as bool) as String |
|---|
| 370 | """ |
|---|
| 371 | Runs the given external command with the given args. |
|---|
| 372 | Sets the process to the instance of Process created for this purpose. |
|---|
| 373 | Returns the output, which is also displayed if displayOutput is true. |
|---|
| 374 | Does not check process.exitCode. |
|---|
| 375 | """ |
|---|
| 376 | print 'run: [command] [args]' |
|---|
| 377 | _lastCommand = command + ' ' + args |
|---|
| 378 | p = Process() |
|---|
| 379 | p.startInfo.fileName = command |
|---|
| 380 | p.startInfo.arguments = args |
|---|
| 381 | output = CobraCore.runAndCaptureAllOutput(p).trim |
|---|
| 382 | process = p |
|---|
| 383 | if displayOutput and output <> '' |
|---|
| 384 | for line in output.replace('\r', '').split(c'\n') |
|---|
| 385 | print ' : [line]' |
|---|
| 386 | print |
|---|
| 387 | return output |
|---|
| 388 | |
|---|
| 389 | def runSnapshotCobra(args as String) as String |
|---|
| 390 | """ |
|---|
| 391 | Runs the Cobra compiler. |
|---|
| 392 | Prints the output and returns it. |
|---|
| 393 | If Cobra gives an error, calls .error. |
|---|
| 394 | """ |
|---|
| 395 | process as Process? |
|---|
| 396 | output = .runSnapshotCobra(args, out process) |
|---|
| 397 | if process.exitCode, .error('Exit code from running SnapshotCobra: [process.exitCode]') |
|---|
| 398 | return output |
|---|
| 399 | |
|---|
| 400 | def runSnapshotCobra(args as String, process as out Process?) as String |
|---|
| 401 | """ |
|---|
| 402 | Runs the Cobra compiler. |
|---|
| 403 | Creates and "returns" the Process instance via the `process` argument. |
|---|
| 404 | Prints the output and returns it. |
|---|
| 405 | This does not exit on any errors. Check the process yourself. |
|---|
| 406 | """ |
|---|
| 407 | return .runCommand(_snapshotCompilerPath to !, args, out process) |
|---|
| 408 | |
|---|
| 409 | def runSourceCobra(args as String) as String |
|---|
| 410 | process as Process? |
|---|
| 411 | output = .runSourceCobra(args, out process) |
|---|
| 412 | if process.exitCode, .error('Exit code from running Source Cobra: [process.exitCode]') |
|---|
| 413 | return output |
|---|
| 414 | |
|---|
| 415 | def runSourceCobra(args as String, process as out Process?) as String |
|---|
| 416 | return .runCommand('cobra.exe', args, out process) |
|---|
| 417 | |
|---|
| 418 | |
|---|
| 419 | ## Stages |
|---|
| 420 | |
|---|
| 421 | def printPlatform |
|---|
| 422 | .startStage('Print Platform Description') |
|---|
| 423 | if .isRunningOnUnix |
|---|
| 424 | .printPlatformCommand('sw_vers') # Mac OS X |
|---|
| 425 | .printPlatformCommand('lsb_release -a') # could try /etc/*-release if this fails |
|---|
| 426 | .printPlatformPairCommand('Uname', 'uname -a') |
|---|
| 427 | else |
|---|
| 428 | .printPlatformPairCommand('WMI Op Sys Ver', 'wmic os get Caption,CSDVersion /value') |
|---|
| 429 | .printPlatformCommand('system info', ['OS Name:', 'OS Version:']) |
|---|
| 430 | .printPlatformPairCommand('Cmd Op Sys Ver', 'ver') |
|---|
| 431 | .printPlatformPair('Virtual Machine', if(CobraCore.isRunningOnMono, 'Mono', '.NET')) |
|---|
| 432 | .printPlatformPair('CLR Version', Assembly.getAssembly(Object).imageRuntimeVersion) |
|---|
| 433 | .printPlatformPair('Env Command Line', Environment.commandLine) |
|---|
| 434 | .printPlatformPair('Env Current Dir', Environment.currentDirectory) |
|---|
| 435 | .printPlatformPair('Env OS Version', Environment.osVersion) |
|---|
| 436 | .printPlatformPair('Env System Dir', Environment.systemDirectory) |
|---|
| 437 | .printPlatformPair('Env Version', Environment.version) |
|---|
| 438 | if .isRunningOnUnix |
|---|
| 439 | .printPlatformPairCommand('Mono', 'mono --version') |
|---|
| 440 | else |
|---|
| 441 | .printPlatformCommand(r'dir %WINDIR%\Microsoft.Net\Framework\v* /O:-N /B') |
|---|
| 442 | print |
|---|
| 443 | |
|---|
| 444 | def printPlatformPair(key as String, value) |
|---|
| 445 | key += ':' |
|---|
| 446 | print '[key.padRight(18)] [value]' |
|---|
| 447 | |
|---|
| 448 | def printPlatformPairCommand(key as String, command as String) |
|---|
| 449 | .printPlatformPair(key, _platformCommand(command)) |
|---|
| 450 | |
|---|
| 451 | def printPlatformCommand(command as String) |
|---|
| 452 | .printPlatformCommand(command, List<of String>()) |
|---|
| 453 | |
|---|
| 454 | def printPlatformCommand(command as String, grepList as IList<of String>) |
|---|
| 455 | output = _platformCommand(command) |
|---|
| 456 | if output is nil, return |
|---|
| 457 | if grepList.count > 0 |
|---|
| 458 | for line in output.splitLines |
|---|
| 459 | found = false |
|---|
| 460 | for grep in grepList |
|---|
| 461 | if line.contains(grep) |
|---|
| 462 | found = true |
|---|
| 463 | break |
|---|
| 464 | if found, _printRawLine(line) |
|---|
| 465 | else |
|---|
| 466 | for line in output.splitLines |
|---|
| 467 | _printRawLine(line) |
|---|
| 468 | |
|---|
| 469 | def _platformCommand(command as String) as String? |
|---|
| 470 | # fails silently as some platform commands may not be available |
|---|
| 471 | if ' ' in command |
|---|
| 472 | command, args = command.split(@[c' '], 2) |
|---|
| 473 | else |
|---|
| 474 | args = '' |
|---|
| 475 | p = Process() |
|---|
| 476 | p.startInfo.fileName = command |
|---|
| 477 | p.startInfo.arguments = args |
|---|
| 478 | try |
|---|
| 479 | return CobraCore.runAndCaptureAllOutput(p).trim |
|---|
| 480 | catch |
|---|
| 481 | return nil |
|---|
| 482 | |
|---|
| 483 | def _printRawLine(line as String) |
|---|
| 484 | i = line.indexOf(': ') |
|---|
| 485 | if i == -1, i = line.indexOf(':\t') |
|---|
| 486 | if i <> -1 |
|---|
| 487 | .printPlatformPair(line[:i].trim, line[i+1:].trim) |
|---|
| 488 | else |
|---|
| 489 | print line |
|---|
| 490 | |
|---|
| 491 | def verifyElevatedPermissions |
|---|
| 492 | .startStage('Verify running as admin user') |
|---|
| 493 | if not .isAdmin |
|---|
| 494 | .error('Please run this executable as an admin user.') |
|---|
| 495 | |
|---|
| 496 | def verifyInstallDirectory |
|---|
| 497 | .startStage('Verify installation directory') |
|---|
| 498 | default = if(.isRunningOnUnix, .installDirectories[1], .installDirectories[0]) |
|---|
| 499 | if File.exists(.configFileName) |
|---|
| 500 | # get install directory from first line of the file |
|---|
| 501 | useDir = File.openText(.configFileName).readLine |
|---|
| 502 | if useDir and useDir.trim.length, default = useDir.trim |
|---|
| 503 | # TODO: prompt the user for the location |
|---|
| 504 | .requireDir(default) |
|---|
| 505 | _targetDir = default |
|---|
| 506 | print |
|---|
| 507 | |
|---|
| 508 | def verifyInWorkspace |
|---|
| 509 | .startStage('Verify running in workspace') |
|---|
| 510 | msg = 'The current directory does not appear to be a workspace. This program is for installing from the workspace.' |
|---|
| 511 | if not File.exists('Compiler.cobra'), .error(msg) |
|---|
| 512 | if not Directory.exists('Snapshot'), .error(msg) |
|---|
| 513 | print 'Verified.' |
|---|
| 514 | print |
|---|
| 515 | |
|---|
| 516 | def askNet4 |
|---|
| 517 | .startStage('.NET 4.0 Prompt') |
|---|
| 518 | if _willForceDotNet4 |
|---|
| 519 | print '-net4 was passed on the command line' |
|---|
| 520 | answer = 'y' |
|---|
| 521 | else |
|---|
| 522 | print 'Cobra can be installed for .NET 2.0/3.0/3.5 or .NET 4.0.' |
|---|
| 523 | default = 'n' |
|---|
| 524 | if CobraCore.isRunningOnMono |
|---|
| 525 | mono = CobraCore.monoVersionString |
|---|
| 526 | if mono and mono.length >= 'x.y'.length |
|---|
| 527 | if mono.startsWith('3.') |
|---|
| 528 | default = 'y' |
|---|
| 529 | else if mono.startsWith('2.') and mono.split(c'.')[1] in ['10', '11', '12'] |
|---|
| 530 | default = 'y' |
|---|
| 531 | else if .isRunningOnWindows |
|---|
| 532 | # windowsPath = Environment.getFolderPath(Environment.SpecialFolder.Windows) # .NET 4 only |
|---|
| 533 | windowsPath = Environment.getEnvironmentVariable('WINDIR') ? Environment.getEnvironmentVariable('SYSTEMROOT') |
|---|
| 534 | if windowsPath |
|---|
| 535 | net4Path = Path.combine(windowsPath, r'Microsoft.NET\Framework\v4.0.30319\csc.exe') |
|---|
| 536 | if File.exists(net4Path), default = 'y' |
|---|
| 537 | while true |
|---|
| 538 | print 'Do you want to install for .NET 4.0? \[[default]] ' stop |
|---|
| 539 | answer = Console.readLine.trim |
|---|
| 540 | if answer == '', answer = default |
|---|
| 541 | answer = answer[0].toString.toLower |
|---|
| 542 | if answer in 'yn', break |
|---|
| 543 | print |
|---|
| 544 | if answer == 'y' |
|---|
| 545 | _willForceDotNet4 = true |
|---|
| 546 | .setUpCLR4(_args) |
|---|
| 547 | |
|---|
| 548 | def verifyVirtualMachineVersion |
|---|
| 549 | if CobraCore.isRunningOnMono |
|---|
| 550 | .startStage('Verify Novell Mono version') |
|---|
| 551 | minMonoVersion = if(_willForceDotNet4, '2.10', '2.6') |
|---|
| 552 | vers = CobraCore.monoVersionString |
|---|
| 553 | if vers is nil or vers.trim == '' |
|---|
| 554 | .error('Cannot determine Mono version. Please install Mono [minMonoVersion] or higher.') |
|---|
| 555 | else |
|---|
| 556 | print 'Mono Version', vers |
|---|
| 557 | parts = vers.split(c'.') |
|---|
| 558 | if parts and parts[0] >= '2' |
|---|
| 559 | print 'Verified >= [minMonoVersion]' |
|---|
| 560 | print |
|---|
| 561 | else |
|---|
| 562 | .error('Mono version must be [minMonoVersion] or higher.') |
|---|
| 563 | |
|---|
| 564 | def locateSnapshotCompiler |
|---|
| 565 | .startStage('Locate and test Cobra Snapshot compiler') |
|---|
| 566 | _snapshotCompilerPath = 'Snapshot[.slash]cobra.exe' |
|---|
| 567 | if not File.exists(_snapshotCompilerPath) |
|---|
| 568 | .error('Cannot locate [_snapshotCompilerPath].') |
|---|
| 569 | # Not needed; clutters the output; tends to obscure when the Snapshot is being used; |
|---|
| 570 | # _snapshotCompilerPath = Path.getFullPath(_snapshotCompilerPath) |
|---|
| 571 | output = .runSnapshotCobra('-about') |
|---|
| 572 | assert 'The Cobra Programming Language' in output |
|---|
| 573 | assert 'Copyright' in output |
|---|
| 574 | assert 'Usage' in output |
|---|
| 575 | |
|---|
| 576 | def locateGacUtil(startStage as bool) |
|---|
| 577 | if startStage, .startStage('Locate gacutil.exe') |
|---|
| 578 | errorMsg = 'Cannot locate a gacutil. Maybe you can try again using the "Visual Studio Command Prompt" or ".NET SDK Command Prompt".' |
|---|
| 579 | if _willForceDotNet4 and .isRunningOnCLR2 and .isRunningOnWindows |
|---|
| 580 | programFilesDir = Environment.getFolderPath(Environment.SpecialFolder.ProgramFiles) |
|---|
| 581 | if programFilesDir.length >= 2 |
|---|
| 582 | drive = programFilesDir[0].toString |
|---|
| 583 | else |
|---|
| 584 | drive = 'C' |
|---|
| 585 | # the following is wrong as it will be gacutil 3.5: |
|---|
| 586 | # gacutil = drive + r':\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\GacUtil.exe' |
|---|
| 587 | # gacutil 4.0 lives here: |
|---|
| 588 | gacutil = drive + r':\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\GacUtil.exe' |
|---|
| 589 | if File.exists(gacutil) |
|---|
| 590 | _gacutil = gacutil |
|---|
| 591 | return |
|---|
| 592 | .error(errorMsg) |
|---|
| 593 | slash = .slash |
|---|
| 594 | gacutil = 'gacutil' |
|---|
| 595 | p = Process() |
|---|
| 596 | p.startInfo.fileName = gacutil |
|---|
| 597 | p.startInfo.arguments = '-silent' |
|---|
| 598 | try |
|---|
| 599 | CobraCore.runAndCaptureAllOutput(p) |
|---|
| 600 | found = true |
|---|
| 601 | print 'found in system PATH' |
|---|
| 602 | catch FileNotFoundException |
|---|
| 603 | pass |
|---|
| 604 | catch ComponentModel.Win32Exception |
|---|
| 605 | pass |
|---|
| 606 | |
|---|
| 607 | if not found |
|---|
| 608 | # try to find the gacutil |
|---|
| 609 | print 'Searching for gacutil...' |
|---|
| 610 | gacutil = 'gacutil.exe' |
|---|
| 611 | |
|---|
| 612 | dirs = [ |
|---|
| 613 | r'Microsoft.NET\SDK\v2.0\bin', # VS 2005 / SDK .NET 2.0 |
|---|
| 614 | r'Microsoft SDKs\Windows\v6.0A\bin', # VS 2008 |
|---|
| 615 | r'Microsoft Visual Studio 8\SDK\v2.0\Bin', |
|---|
| 616 | ] |
|---|
| 617 | |
|---|
| 618 | # search %ProgramFiles% (which can differ internationally) |
|---|
| 619 | programFilesDir = Environment.getFolderPath(Environment.SpecialFolder.ProgramFiles) |
|---|
| 620 | for dir in dirs |
|---|
| 621 | path = '[programFilesDir][slash][dir][slash][gacutil]' |
|---|
| 622 | print 'checking:', path |
|---|
| 623 | if File.exists(path) |
|---|
| 624 | print 'found:', path |
|---|
| 625 | gacutil = path |
|---|
| 626 | found = true |
|---|
| 627 | break |
|---|
| 628 | # else, print path |
|---|
| 629 | |
|---|
| 630 | if not found |
|---|
| 631 | for dir in dirs |
|---|
| 632 | # search drives for X:\Program Files\... |
|---|
| 633 | for drive in Directory.getLogicalDrives |
|---|
| 634 | drive = drive[:1] # normalize to just one character |
|---|
| 635 | if drive <= 'B', continue |
|---|
| 636 | path = '[drive]:[slash]Program Files[slash][dir][slash][gacutil]' |
|---|
| 637 | print 'checking:', path |
|---|
| 638 | if File.exists(path) |
|---|
| 639 | print 'found:', path |
|---|
| 640 | gacutil = path |
|---|
| 641 | found = true |
|---|
| 642 | break |
|---|
| 643 | # else, print path |
|---|
| 644 | if found, break |
|---|
| 645 | |
|---|
| 646 | if not found, .error(errorMsg) |
|---|
| 647 | _gacutil = gacutil |
|---|
| 648 | if startStage, print |
|---|
| 649 | |
|---|
| 650 | def buildCobraCompiler |
|---|
| 651 | .startStage('Build new Cobra compiler') |
|---|
| 652 | .runSnapshotCobra('-compile [.compileFlags] -ert:yes cobra.cobra -files:files-to-compile.text') |
|---|
| 653 | if not File.exists('cobra.exe'), .error('No cobra.exe file was produced.') |
|---|
| 654 | |
|---|
| 655 | def getBaseVersion |
|---|
| 656 | .startStage('Retrieve Cobra base version number') |
|---|
| 657 | # It's called "base version" because it doesn't include any text after the numbers |
|---|
| 658 | # "0.8.0 post release" --> "0.8.0" |
|---|
| 659 | output = .runSourceCobra('-version') |
|---|
| 660 | reMatch = Regex.match(output, r'svn:(\d+)') |
|---|
| 661 | if reMatch.success |
|---|
| 662 | assert reMatch.value |
|---|
| 663 | _baseVersion = 'svn-' + reMatch.groups[1].toString |
|---|
| 664 | else |
|---|
| 665 | reMatch = Regex.match(output, r'\d+\.\d+\.\d+') |
|---|
| 666 | if reMatch.success |
|---|
| 667 | assert reMatch.value |
|---|
| 668 | _baseVersion = reMatch.value |
|---|
| 669 | else |
|---|
| 670 | .error('Could not extract base version number.') |
|---|
| 671 | _baseVersion += '-post' |
|---|
| 672 | # check for an informal release |
|---|
| 673 | parent = Path.getFullPath('..') |
|---|
| 674 | if File.exists('[parent][.slash]InformalRelease.text') |
|---|
| 675 | output = File.readAllText('[parent][.slash]InformalRelease.text') |
|---|
| 676 | re = Regex(r'\d+\-\d+\-\d+') |
|---|
| 677 | reMatch = re.match(output) |
|---|
| 678 | if reMatch.success |
|---|
| 679 | assert reMatch.value |
|---|
| 680 | _baseVersion += '-' + reMatch.value |
|---|
| 681 | else |
|---|
| 682 | .error('Could not extract date from InformalRelease.text') |
|---|
| 683 | print 'base version: [_baseVersion]' |
|---|
| 684 | print |
|---|
| 685 | |
|---|
| 686 | def installLibrary(name as String, flags as String, files as String) |
|---|
| 687 | .buildLibrary(name, flags, files as String) |
|---|
| 688 | .installLibraryToGAC(name) |
|---|
| 689 | .verifyGacInstallation(name) |
|---|
| 690 | |
|---|
| 691 | def buildLibrary(name as String, flags as String, files as String) |
|---|
| 692 | """ |
|---|
| 693 | Builds the copy of the Cobra Standard Library for installation to the GAC. |
|---|
| 694 | Must build the library using the Source cobra.exe, not the Snapshot |
|---|
| 695 | Always build with -debug since this is the copy for GAC installation. The debug info (mdb file) |
|---|
| 696 | will be installed to the GAC along with the dll. This is required for the -d compiler option. |
|---|
| 697 | """ |
|---|
| 698 | .startStage('Build [name] library') |
|---|
| 699 | .runSourceCobra('[flags] -debug [.compileFlags] -out:[name].dll -key-file:Cobra.Lang[.slash]Cobra.Lang.snk [files]') |
|---|
| 700 | |
|---|
| 701 | def installLibraryToGAC(name as String) |
|---|
| 702 | .startStage('Install [name] library to the GAC') |
|---|
| 703 | dllName = name + '.dll' |
|---|
| 704 | if _willForceDotNet4 and .isRunningOnCLR2 and .isRunningOnWindows |
|---|
| 705 | # have to run gacutil command line |
|---|
| 706 | .locateGacUtil(false) |
|---|
| 707 | .runCommand(_gacutil, '-i [dllName] -f') |
|---|
| 708 | else |
|---|
| 709 | try |
|---|
| 710 | print 'Invoking Publish.GacInstall...' |
|---|
| 711 | Publish().gacInstall(dllName) |
|---|
| 712 | print 'Done.' |
|---|
| 713 | print |
|---|
| 714 | catch NotImplementedException |
|---|
| 715 | print 'Not implemented exception.' |
|---|
| 716 | print 'Will attempt to use gacutil.exe.' |
|---|
| 717 | .locateGacUtil(false) |
|---|
| 718 | .runCommand(_gacutil, '-i [dllName] -f') |
|---|
| 719 | catch e as Exception |
|---|
| 720 | print '[e.getType] e.message' |
|---|
| 721 | |
|---|
| 722 | def verifyGacInstallation(name as String) |
|---|
| 723 | # TODO: verify the version number: Cobra.Lang, Version=0.0.1.0 |
|---|
| 724 | dllName = name + '.dll' |
|---|
| 725 | .startStage('Verifying [dllName] installed to the GAC') |
|---|
| 726 | if _willForceDotNet4 and .isRunningOnCLR2 |
|---|
| 727 | print 'Skipping due to running on .NET 2, but installed for .NET 4.' |
|---|
| 728 | print |
|---|
| 729 | return |
|---|
| 730 | try |
|---|
| 731 | # temporarily rename the standard library to ensure that assembly |
|---|
| 732 | # loading is attempted from the GAC. |
|---|
| 733 | tmpFileName = 'temp-[Process.getCurrentProcess.id]-[dllName]' |
|---|
| 734 | File.move(dllName, tmpFileName) |
|---|
| 735 | # avoid warning: "System.Reflection.Assembly.LoadWithPartialName(string)" is obsolete |
|---|
| 736 | # a = Assembly.loadWithPartialName(name) |
|---|
| 737 | # with dynamic binding: |
|---|
| 738 | assemblyType = Assembly to dynamic |
|---|
| 739 | a = assemblyType.loadWithPartialName(name) |
|---|
| 740 | if a is nil |
|---|
| 741 | .error('After installing the library "[name]", it cannot be loaded.') |
|---|
| 742 | if a.globalAssemblyCache |
|---|
| 743 | print '[dllName] has been successfully installed to the GAC.' |
|---|
| 744 | else |
|---|
| 745 | .warning('After installing the library "[name]", it can be loaded, but does not report that it is in the GAC.') |
|---|
| 746 | File.move(tmpFileName, dllName) |
|---|
| 747 | catch NotImplementedException |
|---|
| 748 | print 'Attempting to use gacutil.' |
|---|
| 749 | if not _gacutil, .locateGacUtil(false) |
|---|
| 750 | output = .runCommand(_gacutil, '-l Cobra.Lang') |
|---|
| 751 | if '[dllName], Version=' in output |
|---|
| 752 | print '[dllName] has been successfully installed to the GAC.' |
|---|
| 753 | else |
|---|
| 754 | .error('Installing the library "[name]" to the GAC was unsuccessful.') |
|---|
| 755 | print |
|---|
| 756 | |
|---|
| 757 | def verifyNewlyBuiltCobra |
|---|
| 758 | .startStage('Verify newly built Cobra compiler') |
|---|
| 759 | .runSourceCobra('-about') |
|---|
| 760 | msg = 'Cannot run hello.cobra with new compiler.' |
|---|
| 761 | if not _skipStdLib |
|---|
| 762 | if File.exists('hello.exe'), File.delete('hello.exe') # fresh start |
|---|
| 763 | File.copy('Misc[.slash]hello.cobra', 'hello.cobra', true) |
|---|
| 764 | hello = 'hello.cobra' |
|---|
| 765 | output = .runSourceCobra('-ert:no [hello]') |
|---|
| 766 | if not output.startsWith('Hello'), .error(msg) |
|---|
| 767 | output = .runSourceCobra('[hello]') |
|---|
| 768 | if not output.startsWith('Hello'), .error(msg) |
|---|
| 769 | output = .runSourceCobra('-ert:yes [hello]') |
|---|
| 770 | if not output.startsWith('Hello'), .error(msg) |
|---|
| 771 | |
|---|
| 772 | def copyFilesToInstallDirectory |
|---|
| 773 | require _targetDir is not nil |
|---|
| 774 | .startStage('Copy files to install directory') |
|---|
| 775 | slash = .slash |
|---|
| 776 | targetDir = _targetDir |
|---|
| 777 | |
|---|
| 778 | if targetDir, .requireDir(targetDir) |
|---|
| 779 | if Directory.exists(Path.combine(targetDir, 'Source')) |
|---|
| 780 | print 'The directory "[targetDir]" appears to contain a workspace or snapshot of the' |
|---|
| 781 | print 'Cobra source code, due to containing the subdirectory "Source".' |
|---|
| 782 | print 'Installing to that location can lead to confusion and technical difficulties.' |
|---|
| 783 | print 'Consider clearing out "[targetDir]" and creating a workspace *inside* it called,' |
|---|
| 784 | print 'for example, "Workspace".' |
|---|
| 785 | print |
|---|
| 786 | .error('Cannot install to workspace or workspace snapshot. See message above.') |
|---|
| 787 | |
|---|
| 788 | versionDir = '[targetDir][slash]Cobra-[_baseVersion]' # ex: /usr/local/cobra/Cobra-0.8.0-post |
|---|
| 789 | .deleteDir(versionDir) |
|---|
| 790 | .requireDir(versionDir) |
|---|
| 791 | _versionDir = versionDir |
|---|
| 792 | |
|---|
| 793 | # TODO: readme file? |
|---|
| 794 | parent = Path.getFullPath('..') |
|---|
| 795 | |
|---|
| 796 | versionOutput = '' |
|---|
| 797 | if File.exists('[parent][slash]InformalRelease.text') |
|---|
| 798 | versionOutput = File.readAllText('[parent][slash]InformalRelease.text') |
|---|
| 799 | else if File.exists('.svn') or File.exists('_svn') |
|---|
| 800 | # record "svn info" in the installation directory |
|---|
| 801 | svnFailed = 'Cannot find Subversion revision information. The svn program is not installed or it failed. This only means that the revision number of the workspace is not recorded in the installation directory for your convenience. The compiler and libraries do not rely on this.' |
|---|
| 802 | try |
|---|
| 803 | process as Process? |
|---|
| 804 | versionOutput = .runCommand('svn', 'info', out process, false) |
|---|
| 805 | if process.exitCode |
|---|
| 806 | print '"svn info" failed. Check your svn installation.' |
|---|
| 807 | print '[versionOutput]' |
|---|
| 808 | print |
|---|
| 809 | .warning(svnFailed) |
|---|
| 810 | catch ex as SystemException |
|---|
| 811 | # user could be on TortoiseSVN |
|---|
| 812 | print 'svn is not installed or it is not in the PATH. ', ex.message |
|---|
| 813 | .warning(svnFailed) |
|---|
| 814 | if versionOutput <> '' |
|---|
| 815 | fileName = '[versionDir][slash]Version.text' |
|---|
| 816 | print 'writing :', fileName |
|---|
| 817 | File.writeAllText(fileName, versionOutput) |
|---|
| 818 | print |
|---|
| 819 | |
|---|
| 820 | for dir in ['HowTo', 'Reusables', 'Samples', 'Supplements'] |
|---|
| 821 | .copyContents('[parent][slash][dir]', '[versionDir][slash][dir]') |
|---|
| 822 | |
|---|
| 823 | versionBinDir = '[versionDir][slash]bin' |
|---|
| 824 | .requireDir(versionBinDir) |
|---|
| 825 | print 'copy bin: [versionBinDir]' |
|---|
| 826 | binFiles = 'cobra.exe Cobra.Lang.dll Cobra.Sharp.*.dll WebAssets styles-cobra-doc.css styles-cobra-help.css styles-cobra-shl.css styles-exception-report.css styles-output-html.css'.split |
|---|
| 827 | for fileName in binFiles |
|---|
| 828 | if Directory.exists(fileName) |
|---|
| 829 | .copyContents(fileName, '[versionBinDir][slash][fileName]') |
|---|
| 830 | else |
|---|
| 831 | for fileName2 in Directory.getFiles('.', fileName) # glob |
|---|
| 832 | File.copy(fileName2, '[versionBinDir][slash][fileName2]') |
|---|
| 833 | |
|---|
| 834 | .copyContents('Cobra.Lang', '[versionBinDir][slash]Cobra.Lang') |
|---|
| 835 | |
|---|
| 836 | # delete _svn or .svn from the installation directory |
|---|
| 837 | .findAndDeleteDir(versionDir, '_svn') |
|---|
| 838 | .findAndDeleteDir(versionDir, '.svn') |
|---|
| 839 | |
|---|
| 840 | # create cobra.bat / cobra for invoking the latest version |
|---|
| 841 | baseBinDir = '[targetDir][slash]bin' |
|---|
| 842 | .requireDir(baseBinDir) |
|---|
| 843 | if .isRunningOnUnix |
|---|
| 844 | _cobraCommandPath = '[baseBinDir][slash]cobra' |
|---|
| 845 | print 'writing :', _cobraCommandPath |
|---|
| 846 | using f = File.createText(_cobraCommandPath) |
|---|
| 847 | f.writeLine('#!/bin/sh') |
|---|
| 848 | f.writeLine('exec mono "[versionDir][slash]bin[slash]cobra.exe" "$@"') |
|---|
| 849 | .runCommand('chmod', "a+x '[_cobraCommandPath]'") |
|---|
| 850 | else |
|---|
| 851 | _cobraCommandPath = '[baseBinDir][slash]cobra.bat' |
|---|
| 852 | print 'writing :', _cobraCommandPath |
|---|
| 853 | using f = File.createText(_cobraCommandPath) |
|---|
| 854 | f.writeLine('@"[versionDir][slash]bin[slash]cobra.exe" %*') |
|---|
| 855 | print |
|---|
| 856 | |
|---|
| 857 | def verifyNewlyInstalledCobra |
|---|
| 858 | .startStage('Verify newly installed Cobra compiler') |
|---|
| 859 | output = .runCommand(_cobraCommandPath, '-about', true) |
|---|
| 860 | if not output.startsWith('The Cobra Programming Language') |
|---|
| 861 | .error('Cannot run the installed Cobra with -about') |
|---|
| 862 | output = .runCommand(_cobraCommandPath, '-ert:yes Misc[.slash]hello.cobra', true) |
|---|
| 863 | if not output.startsWith('Hello') |
|---|
| 864 | .error('Cannot run the installed Cobra on "hello.cobra"') |
|---|
| 865 | |
|---|
| 866 | def cleanUpWorkspace |
|---|
| 867 | .startStage('Clean up workspace') |
|---|
| 868 | # By removing cobra.exe and friends from the workspace, |
|---|
| 869 | # we minimize the chances that the user runs the local Cobra compiler |
|---|
| 870 | # instead of the installed one. |
|---|
| 871 | fileNames = ['cobra.exe'] |
|---|
| 872 | for lib in .libs, fileNames.add(lib['name'] + '.dll') |
|---|
| 873 | for fileName in fileNames |
|---|
| 874 | for ext in ['', '.mdb', '.pdb'] |
|---|
| 875 | try, File.delete(fileName+ext) |
|---|
| 876 | catch Exception, pass |
|---|
| 877 | |
|---|
| 878 | def installInPath |
|---|
| 879 | .startStage('Install "cobra" into a system path directory') |
|---|
| 880 | commandName = if(.isRunningOnUnix, 'cobra', 'cobra.bat') |
|---|
| 881 | slash = .slash |
|---|
| 882 | paths = (Environment.getEnvironmentVariable('PATH') ? '').split(Path.pathSeparator).toList |
|---|
| 883 | for commandDir in paths |
|---|
| 884 | if commandDir == '.', continue # skip the 'cobra' in the <workspace>/Source directory |
|---|
| 885 | # print 'checking path:', commandDir |
|---|
| 886 | if commandDir.startsWith('~') |
|---|
| 887 | home = Environment.getEnvironmentVariable('HOME') |
|---|
| 888 | if home, commandDir = home + commandDir[1:] |
|---|
| 889 | commandPath = Path.getFullPath('[commandDir][slash][commandName]') |
|---|
| 890 | if File.exists(commandPath) |
|---|
| 891 | print 'found in PATH:', commandPath |
|---|
| 892 | found = true |
|---|
| 893 | break |
|---|
| 894 | # print |
|---|
| 895 | baseBinDir = '[_targetDir][slash]bin' |
|---|
| 896 | if found |
|---|
| 897 | if String.compare(commandPath, '[baseBinDir][slash][commandName]', not .isRunningOnUnix) == 0 |
|---|
| 898 | # e.g., if the PATH already points to the install directory |
|---|
| 899 | print 'Your PATH already contains [baseBinDir]' |
|---|
| 900 | print 'so you can invoke "cobra" from any directory.' |
|---|
| 901 | else |
|---|
| 902 | if .newlyCompiledFileIsSymlinkedFromOneFoundOnPath(_cobraCommandPath, commandPath) |
|---|
| 903 | print 'The existing "cobra" in your path is the correct' |
|---|
| 904 | print 'symbolic link and has not been changed.' |
|---|
| 905 | else |
|---|
| 906 | .copyCobraCommandTo(commandPath, true) |
|---|
| 907 | else if '/usr/local/bin' in paths |
|---|
| 908 | .copyCobraCommandTo('/usr/local/bin/[commandName]', false) |
|---|
| 909 | else |
|---|
| 910 | # TODO: on unix, create a symlink in /usr/local/bin or /usr/bin if they exist and are in the path |
|---|
| 911 | print 'The Cobra compiler is not in your PATH. To remedy you can:' |
|---|
| 912 | print '1. Add [Path.getDirectoryName(_cobraCommandPath)] to your PATH' |
|---|
| 913 | print '2. Copy [_cobraCommandPath] to any directory in your PATH' |
|---|
| 914 | |
|---|
| 915 | def newlyCompiledFileIsSymlinkedFromOneFoundOnPath(cobraCommandPath, commandPath) as bool |
|---|
| 916 | if .isRunningOnUnix |
|---|
| 917 | monoAssembly = Assembly.load('Mono.Posix, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756') |
|---|
| 918 | unixFileSystemInfo = monoAssembly.getType('Mono.Unix.UnixFileSystemInfo') to dynamic |
|---|
| 919 | if unixFileSystemInfo |
|---|
| 920 | fileInfo = unixFileSystemInfo.getFileSystemEntry(commandPath) |
|---|
| 921 | if fileInfo.isSymbolicLink and fileInfo.contentsPath == cobraCommandPath |
|---|
| 922 | return true |
|---|
| 923 | return false |
|---|
| 924 | |
|---|
| 925 | def copyCobraCommandTo(commandPath as String, alreadyExisted as bool) |
|---|
| 926 | require commandPath.length |
|---|
| 927 | print 'copy from:', _cobraCommandPath |
|---|
| 928 | print ' to:', commandPath |
|---|
| 929 | try, File.delete(commandPath) |
|---|
| 930 | catch Exception, pass |
|---|
| 931 | File.copy(_cobraCommandPath, commandPath, true) |
|---|
| 932 | print |
|---|
| 933 | if alreadyExisted |
|---|
| 934 | print 'The existing "cobra" in your path at' |
|---|
| 935 | print commandPath |
|---|
| 936 | print 'has been replaced with the new one.' |
|---|
| 937 | else |
|---|
| 938 | print 'The "cobra" command has been installed in your PATH at' |
|---|
| 939 | print commandPath |
|---|
| 940 | |
|---|