/*______________ | ______ | U I Z E J A V A S C R I P T F R A M E W O R K | / / | --------------------------------------------------- | / O / | MODULE : Uize.Build.Wsh Package | / / / | | / / / /| | ONLINE : http://uize.com | /____/ /__/_| | COPYRIGHT : (c)2005-2014 UIZE | /___ | LICENSE : Available under MIT License or GNU General Public License |_______________| http://uize.com/license.html */ /* Module Meta Data type: Package importance: 7 codeCompleteness: 80 docCompleteness: 80 */ /*? Introduction The =Uize.Build.Wsh= package is designed to run in the context of Windows Script Host and provides methods for recursing folder structures and building files. *DEVELOPERS:* `Chris van Rensburg` The =Uize.Build.Wsh= module is used by a few build scripts. It will only be of interest to you if you're writing or modifying build scripts that only run in the Windows Script Host environment. */ Uize.module ({ name:'Uize.Build.Wsh', builder:function () { 'use strict'; var /*** Variables for Scruncher Optimization ***/ _undefined, _wshShell, _fileSystemObject, /*** references to static methods used internally ***/ _getScriptFolderPath, _readFile, _writeFile, _exec ; /*** Utility Functions ***/ function _getFileSystemObject (_params) { return ( (_params && _params.fileSystemObject) || _fileSystemObject || (_fileSystemObject = new ActiveXObject ('Scripting.FileSystemObject')) ); } function _getWshShell () { return _wshShell || (_wshShell = new ActiveXObject ('WScript.Shell')); } return Uize.package ({ getScriptFolderPath:_getScriptFolderPath = function () { return WScript.ScriptFullName.slice (0,-WScript.ScriptName.length - 1); /*? Static Methods Uize.Build.Wsh.getScriptFolderPath Returns a string, representing the folder path for the folder from which the current script is being executed. SYNTAX ............................................................ scriptFolderPathSTR = Uize.Build.Wsh.getScriptFolderPath (); ............................................................ */ }, readFile:_readFile = function (_params) { var _fileSystemObject = _getFileSystemObject (_params), _path = typeof _params == 'string' ? _params : _params.path ; if (_fileSystemObject.GetFile (_path).Size) { var _file = _fileSystemObject.OpenTextFile (_path,1), _text = _file.ReadAll () ; _file.Close (); return _text; } return ''; /*? Static Methods Uize.Build.Wsh.readFile Reads the file at the specified file path and returns its entire contents as a string. SYNTAX .................................................... fileTextSTR = Uize.Build.Wsh.readFile ({ path:filePathSTR, fileSystemObject:fileSystemObjectOBJ // optional }); .................................................... VARIATION .................................................... fileTextSTR = Uize.Build.Wsh.readFile (filePathSTR); .................................................... When a =filePathSTR= parameter is specified in place of an object parameter, then the file will be read at the path specified by this string parameter, and a file system object will be created as needed. NOTES - the file path, specified in the =path= parameter, can be relative to the folder in which the build script is executing - the optional =fileSystemObject= parameter should specify an instance of =Scripting.FileSystemObject= - see also the =Uize.Build.Wsh.writeFile= static method */ }, writeFile:_writeFile = function (_params) { var _path = _params.path, _fileSystemObject = _getFileSystemObject (_params) ; /*** make sure path exists (if not, create it) ***/ var _folderPath = _path.substr (0,_path.lastIndexOf ('\\')); if (!_fileSystemObject.FolderExists (_folderPath)) { var _pathSegments = _folderPath.split ('\\'), _currentPath = _pathSegments [0] // this should be a drive letter ... this code might break if it isn't ; for ( var _pathSegmentNo = 0, _pathSegmentsLength = _pathSegments.length; ++_pathSegmentNo < _pathSegmentsLength; ) { _currentPath += '\\' + _pathSegments [_pathSegmentNo]; _fileSystemObject.FolderExists (_currentPath) || _fileSystemObject.CreateFolder (_currentPath); } } /*** write text to file and close ***/ var _file = _fileSystemObject.CreateTextFile (_path); _file.Write (_params.text); _file.Close (); /*? Static Methods Uize.Build.Wsh.writeFile Writes the specified text string to the specified file path. SYNTAX .................................................... Uize.Build.Wsh.writeFile ({ path:filePathSTR, text:fileTextSTR, fileSystemObject:fileSystemObjectOBJ // optional }); .................................................... If no file exists at the path specified in the =path= parameter, then the file path will be created. This includes creating any folders that may not exist, leading up to the actual file itself. If the file does already exist, it will be overwritten. NOTES - the file path, specified in the =path= parameter, can be relative to the folder in which the build script is executing - the optional =fileSystemObject= parameter should specify an instance of =Scripting.FileSystemObject= - see also the =Uize.Build.Wsh.readFile= static method */ }, buildFiles:function (_params) { var _alwaysBuild = _params.alwaysBuild, _dryRun = _params.dryRun, _fileSystemObject = _getFileSystemObject (_params), _buildScriptName = WScript.ScriptName, _buildScriptFullName = WScript.ScriptFullName, _doNotEnter = _params.doNotEnter, _logChunks = [] ; if (Uize.isArray (_doNotEnter)) _doNotEnter = new RegExp ('\\\\(' + _doNotEnter.join ('|') + ')(\\W|$)') ; function _getFileModifiedTime (_filePath) { return +new Date (_fileSystemObject.GetFile (_filePath).DateLastModified); } function _processFolder (_folderPath) { var _folder = _fileSystemObject.getFolder (_folderPath), _subfolders = new Enumerator (_folder.SubFolders), _targetFolderPath = _doNotEnter && _doNotEnter.test (_folderPath) ? false : _params.targetFolderPathCreator (_folderPath) ; if (typeof _targetFolderPath == 'string') { var _files = new Enumerator (_folder.files); while (!_files.atEnd ()) { var _sourceFilePath = _files.item ().Path; if (_sourceFilePath != _buildScriptFullName) { var _sourceFileName = _sourceFilePath.substr (_sourceFilePath.lastIndexOf ('\\') + 1), _targetFileName = _params.targetFilenameCreator (_sourceFileName) ; if (_targetFileName) { var _targetFilePath = _targetFolderPath + '\\' + _targetFileName, _buildReason = _alwaysBuild ? 'ALWAYS BUILD' : ( _fileSystemObject.FileExists (_targetFilePath) ? ( _getFileModifiedTime (_sourceFilePath) > _getFileModifiedTime (_targetFilePath) ? 'WAS OUT OF DATE' : '' ) : 'DIDN\'T EXIST' ) , _buildDuration, _logDetails = '' ; if (_buildReason) { var _timeBeforeBuild = new Date, _processingResult = _params.fileBuilder (_sourceFileName,_readFile (_sourceFilePath)), _outputText = _processingResult.outputText ; _logDetails = _processingResult.logDetails || ''; !_dryRun && _outputText != _undefined && _writeFile ({path:_targetFilePath,text:_outputText}) ; _buildDuration = new Date - _timeBeforeBuild; } _logChunks.push ( (_buildReason ? '***** ' : '') + _sourceFilePath + '\n' + '\tTARGET FILE: ' + _targetFilePath + '\n' + '\t' + ( _buildReason ? ('BUILT (' + _buildReason + '), BUILD DURATION: ' + _buildDuration + 'ms') : 'no action, file is current' ) + '\n' + _logDetails + '\n' ); } } _files.moveNext (); } } if (_targetFolderPath !== false) { while (!_subfolders.atEnd ()) { _processFolder (_subfolders.item ().Path); _subfolders.moveNext (); } } } _processFolder (_params.rootFolderPath || _getScriptFolderPath ()); _writeFile ({ path:_params.logFilePath || _buildScriptName.replace (/\.js$/,'.log'), text:_logChunks.join ('') }); /*? Static Methods Uize.Build.Wsh.buildFiles Facilitates iterating through a folder hierarchy, processing specific files, and writing the results of processing to a specified log file. SYNTAX .................................................................... Uize.Build.Wsh.buildFiles ({ targetFolderPathCreator:targetFolderPathCreatorFUNC, // REQUIRED targetFilenameCreator:targetFilenameCreatorFUNC, // REQUIRED fileBuilder:fileBuilderFUNC, // REQUIRED rootFolderPath:rootFolderPathSTR, // optional alwaysBuild:alwaysBuildBOOL, // optional doNotEnter:doNotEnterARRAYorREGEXP, // optional fileSystemObject:fileSystemObjectOBJ, // optional logFilePath:logFilePathSTR // optional }); .................................................................... This method starts iterating through files in the folder that contains the build script being executed and then recursively iterates through subfolders. targetFolderPathCreator A function reference, specifying a function that should be used to create a target folder path for the output of the files being built. The function specified by this parameter should expect to receive one string parameter, being the folder path of the files being built. The function should return a string, being the path of the target folder where the built versions of the files should be written. In a special case, if the function returns a boolean, then the files in the current folder being processed will not be built, and the boolean value will determine if the method recurses deeper into the current folder's subfolders. This provides a way to skip building the files in the current folder but recurse deeper, or to ignore a particular folder and all its contents - files *and* subfolders. targetFilenameCreator A function reference, specifying a function that should be used to create the target filenames for the output of the files being built. The function specified by this parameter should expect to receive one string parameter, being the filename of the file being built. The function should return a string, being the target filename for where the built version of the file should be written. If the source file is not to be built, based upon interrogating the source filename (perhaps it's not a type of file that should be built), then the function should return an empty string or the value =false=. fileBuilder A function reference, specifying a function that should be used for processing the source file to create output that should be written as the target file. The function specified by this parameter should expect to receive two string parameters, being the filename of the source file being built and the text contents of that file. The function should return an object containing the property =outputText=, being the output text for the built version of the file, and an optional =logDetails= property that can be used to specify any extra log information to summarize or describe how the file was built. When a file is built, the output of the function specified by the =fileBuilder= parameter will be written as a file of the name determined by the =targetFilenameCreator= function, into a folder of the path determined by the =targetFolderPathCreator= function. rootFolderPath An optional string, specifying the path of a folder to serve as the root folder from which to start building files. NOTES - If no =rootFolderPath= parameter is specified, or if it's value is an empty string, =null=, or =undefined=, then the root folder will be the parent folder of the build script. alwaysBuild An optional boolean, indicating whether or not eligible files should always be built, or whether the need to build should be determined automatically. For any file within the folder hierarchy that would be processed by the =Uize.Build.Wsh.buildFiles= method (given the configuration of this method by all its parameter values), a decision to build the file will normally be made automatically by this method, based upon the target file either not existing or having an older modified date than the source file. This is the behavior for the optional =alwaysBuild= parameter's default value of =false=. When the value =true= is specified, then the file will always be built, even if it is considered to have been previously built and up-to-date. doNotEnter An optional array or regular expression, specifying a folder (or folders) that should not be entered when recursing through the folder hierarchy. Any folders specified by this parameter will terminate recursion at that point in the folder tree, and any folders contained inside these dead end folders will not be processed. If a regular expression is specified for this parameter, then this regular expression will be tested against the folder name currently being processed by the =Uize.Build.Wsh.buildFiles= method. If the regular expression matches, then the method will not enter the folder. This parameter is useful for build scripts that should ignore files generated by the build script (or other build scripts) and that are stored in a special build directory. Your site project may also contain a folder of build scripts, and you may not wish any build script using the =Uize.Build.Wsh.buildFiles= method to process any of the files contained therein. fileSystemObject An optional object reference, specifying an instance of the =Scripting.FileSystemObject= control that should be used in file I/O operations. An instance can be created with the statement =new ActiveXObject ('Scripting.FileSystemObject')=. When no =fileSystemObject= parameter is specified, then a file system object will be created as needed to serve the needs of the build process. logFilePath An optional string, specifying the filename of a file within the same folder as the build script that should be used for writing out the log of the build process. Basic information is automatically placed into the log file by the =Uize.Build.Wsh.buildFiles= method, but additional information for each built file can be added by returning text for the optional =logDetails= property of your =fileBuilder= function's return object. NOTES - If no =logFilePath= parameter is specified, or if it's value is an empty string, =null=, or =undefined=, then the filename for the log file will be derived from the filename of the build script, with the ".js" file extension replaced with the extension ".log". */ }, exec:_exec = function (_commands) { var _error; if (!Uize.isArray (_commands)) _commands = [_commands]; for ( var _commandNo = -1, _commandsLength = _commands.length, _wshShell = new ActiveXObject ('WScript.Shell'), _errorCode ; ++_commandNo < _commandsLength && !_error; ) if (_errorCode = _wshShell.Run (_commands [_commandNo],0,true)) _error = { script:_commands [_commandNo], errorCode:_errorCode } ; return _error; }, runScripts:function (_scripts) { return _exec ( Uize.map (Uize.isArray (_scripts) ? _scripts : [_scripts],'\'WScript \' + value') ); } }); } });