Below are examples demonstrating how you can collect individual files into a zlib compressed (*.zip) file.
The first example ("Build Data") demonstrates how to use the file system to build a dynamic list of files, relative to a base directory, to include in the *.zip. It also demonstrates how to then pass the data to the second utility script, which actually builds the zip.
The second example ("Utility") demonstrates how a utility type script that can be executed by an external script1) or plugin that passes in arguments could be used to produce zlib compressed archives.
// Define an anonymous function; // serves as our main loop, // limits the scope of variables (function(){ // Define 'static' objects var s_oFileInfo = new DzFileInfo( getScriptFileName() ); /*********************************************************************/ // String : A function for retrieving a translation if one exists function text( sText ) { // If the version of the application supports qsTr() if( typeof( qsTr ) != "undefined" ){ // Return the translated (if any) text return qsTr( sText ); } // Return the original text return sText; }; /*********************************************************************** ***** DsFileSystem Prototype ***** ***********************************************************************/ /*********************************************************************/ function DsFileSystem() { }; /***********************************************************************/ DsFileSystem.superclass = Object; /*********************************************************************/ // Array<String|DzDir> : Method for collecting an array of directory objects DsFileSystem.prototype.getDirectories = function( oDir, regxFilter, nFilter, nSort, sType, bRecurse ) { // Declare working variable var sAbsPath; // Get the directory names var aDirs = oDir.entryList( regxFilter, nFilter, nSort ); // Iterate over the directory names for( var i = 0, nDirs = aDirs.length; i < nDirs; i += 1 ){ // Get the absolute path of the 'current' dir sAbsPath = String( "%1/%2" ).arg( oDir.absPath() ).arg( aDirs[ i ] ); // Based on the type requested switch( sType ){ default: case "String": // Update the name with the absolute path of the directory aDirs[ i ] = sAbsPath; // If we are recursing if( bRecurse ){ // Recursively collect the directory paths aDirs = aDirs.concat( this.getSubDirectories( new DzDir( sAbsPath ), regxFilter, nFilter, nSort, sType ) ); } break; case "DzDir": // Update the name with a directory object aDirs[ i ] = new DzDir( sAbsPath ); // If we are recursing if( bRecurse ){ // Recursively collect the directories aDirs = aDirs.concat( this.getSubDirectories( aDirs[ i ], regxFilter, nFilter, nSort, sType ) ); } break; } } // Return the result return aDirs; }; /*********************************************************************/ // Array<String|DzDir> : Method for recursively collecting an array of directory objects DsFileSystem.prototype.getSubDirectories = function( oDir, regxFilter, nFilter, nSort, sType ) { // Get the immediate child directories var aDirs = this.getDirectories( oDir, regxFilter, nFilter, nSort, sType, true ); // Iterate over the directories for( var i = 0, nDirs = aDirs.length; i < nDirs; i += 1 ){ // Based on the type requested switch( sType ){ default: case "String": // Recursively collect the directory paths aDirs = aDirs.concat( this.getSubDirectories( new DzDir( aDirs[ i ] ), regxFilter, nFilter, nSort, sType ) ); break; case "DzDir": // Recursively collect the directories aDirs = aDirs.concat( this.getSubDirectories( aDirs[ i ], regxFilter, nFilter, nSort, sType, true ) ); break; } } // Return the result return aDirs; }; /*********************************************************************/ // Array<String|DzFileInfo|DzFile> : Method for collecting an array of files DsFileSystem.prototype.getFiles = function( oDir, regxFilter, nFilter, nSort, sType ) { // Declare working variable var sAbsFilePath; // Get the file names var aFiles = oDir.entryList( regxFilter, nFilter, nSort ); // Iterate over the file names for( var i = 0, nFiles = aFiles.length; i < nFiles; i += 1 ){ // Get the absolute path of the 'current' file sAbsFilePath = oDir.absFilePath( aFiles[ i ] ); // Based on the type requested switch( sType ){ default: case "String": // Update the name with the absolute path of a file aFiles[ i ] = sAbsFilePath; break; case "DzFileInfo": // Update the name with a file info object aFiles[ i ] = new DzFileInfo( sAbsFilePath ); break; case "DzFile": // Update the name with a file object aFiles[ i ] = new DzFile( sAbsFilePath ); break; } } // Return the result return aFiles; }; /*********************************************************************/ // Array<String|DzDir> : Method for retrieving a list of directories DsFileSystem.prototype.getDirectoryList = function( sPath, sFilter, sType, bRecurse, bRelative ) { // Declare the output var aDirs = []; // Create a directory object var oBaseDir = new DzDir( sPath ); // If the directory doesn't exist if( !oBaseDir.exists() ){ // We are done... return aDirs; } // Get the directories var aDirs = this.getDirectories( oBaseDir, sFilter, DzDir.Dirs | DzDir.NoDotAndDotDot, DzDir.Name, sType, bRecurse ); // If we do not want relative if( !bRelative ){ // Return the result return aDirs; } // Declare working variable var sAbsPath, sRelPath; var oDir; // Iterate over the directories for( var i = 0, nDirs = aDirs.length; i < nDirs; i += 1 ){ // Based on the type requested switch( sType ){ default: case "String": // Get the 'current' path sAbsPath = aDirs[ i ]; // Get the relative portion of the path sRelPath = sAbsPath.substring( sPath.length ); // Update the path aDirs[ i ] = sRelPath; break; case "DzDir": // Get the 'current' directory oDir = aDirs[ i ]; // Get the path sAbsPath = oDir.path(); // Get the relative portion of the path sRelPath = sAbsPath.substring( sPath.length ); // Update the path oDir.setPath( sRelPath ); // Update the directory aDirs[ i ] = oDir; break; } } // Return the result return aDirs; }; /*********************************************************************/ // Array<String|DzFileInfo|DzFile> : Method for retrieving a list of files DsFileSystem.prototype.getFileList = function( sPath, sFilter, sType, bRecurse ) { // Declare the output var aFiles = []; // Get the directories var aDirs = this.getDirectoryList( sPath, "*", "DzDir", bRecurse ); // Iterate over the directories for( var i = 0, nDirs = aDirs.length; i < nDirs; i += 1 ){ // Append the files from the 'current' directory to the output aFiles = aFiles.concat( this.getFiles( aDirs[ i ], sFilter, DzDir.Files, DzDir.Name, sType ) ); } // Return the result return aFiles; }; /*********************************************************************/ // Declare working variables var sTitle; var sMessage; // Define common strings var sButton = text( "&OK" ); // If the application version is less than 4.9.3.149 if( App.version64 < 0x0004000900030095 ){ // sTitle = "Version Error"; sMessage = String( "This script requires %1 4.9.3.149 or newer to continue." ) .arg( App.appName ) // If the application is showing prompts if( App.showPrompts() ){ // Inform the user MessageBox.information( text( sMessage ), text( sTitle ), sButton ); } // Provide feecback print( sTitle, ":", sMessage ); // We are done.. return; } // var oScript = new DzScript(); // Construct the path of the utility script that performs compression var sCompressScript = String( "%1/%2_Remote" ) .arg( s_oFileInfo.absolutePath() ) .arg( s_oFileInfo.completeBaseName() ); // Attempt to find our script; doing it this way, we can debug with an // ascii file and distribute a binary [encrypted] file with the same name... // without having to update the contents of the script or manually handle // the file extensions; requires 3.0.1.5 or newer var sScriptPath = oScript.getScriptFile( sCompressScript ); // Declare working variables var sAppData; var sBuild; var sSrcBasePath; var sAbsPath; var sRelPath; var sLayoutsPath; var sSrcPath; var sTgtPath; var aRelPaths; var aFiles; var nFiles; var oDir; var oFileSystem; var oData; // If a script is found if( !sScriptPath.isEmpty() ){ // Get the "AppData" path sAppData = System.getenv( "AppData" ); // If this is on Windows if( App.platform() == DzApp.Windows ){ // Replace backslashes with forward slashes sAppData = sAppData.replace( new RegExp( "\\\\", "g" ), "/" ); } // Initialize the build sBuild = "Studio4"; // Depending on the release cycle, update switch( App.releaseCycle() ){ default: case DzApp.GeneralRelease: break; case DzApp.PublicBuild: case DzApp.PublishingBuild: case DzApp.PrivateBuild: case DzApp.DevBuild: sBuild += " " + App.releaseCycleString(); break; } // Define the source directory path sSrcBasePath = String("%1/%2/%3") .arg( sAppData ) .arg( App.orgName ) .arg( sBuild ); // Create a directory object oDir = new DzDir( sSrcBasePath ); // If the directory does not exist if( !oDir.exists() ){ // Provide feedback print( sSrcBasePath, "does not exist!" ); // We are done... return; } // Let the user know we are busy setBusyCursor(); // Define the target filename sTgtPath = "c:/temp/DS_Layouts_Backup.zip"; // Define the list of relative paths to zip aRelPaths = [ "actions.dsx", "customactions.dsx", "layout.dse", "layout.dsx", "menus.dsx", "toolbars.dsx" ]; // Construct the user layouts path sLayoutsPath = String( "%1/user layouts" ).arg( sSrcBasePath ); // Create a file system object oFileSystem = new DsFileSystem(); // Get all of the files in the directory aFiles = oFileSystem.getFileList( sLayoutsPath, "*", "String", true ); // Iterate over the files for( var i = 0, nFiles = aFiles.length; i < nFiles; i += 1 ){ // Get the 'current' file sAbsPath = aFiles[ i ]; // Get the relative portion of the path sRelPath = sAbsPath.substring( sSrcBasePath.length + 1 ); // Update with the relative path aFiles[ i ] = sRelPath; } // Append any user layouts found aRelPaths = aRelPaths.concat( aFiles ); /// Get the number of files nFiles = aRelPaths.length; // Initialize our data object oData = { "target_path": sTgtPath, "source_paths": new Array( nFiles ), "relative_paths": new Array( nFiles ) //, "run_silent": true }; // Iterate over the relative paths for( var i = 0; i < nFiles; i += 1 ){ // Get the 'current' relative path sRelPath = aRelPaths[ i ]; // Capture the value oData[ "relative_paths" ][i] = sRelPath; // Construct the 'current' source file path sSrcPath = String( "%1/%2" ).arg( sSrcBasePath ).arg( sRelPath ); // Capture the value oData[ "source_paths" ][i] = sSrcPath; } // Let the user know we are done clearBusyCursor(); //print( JSON.stringify( oData, null, "\t" ) ); // If the script loads if( oScript.loadFromFile( sScriptPath ) ){ // Execute the script; pass in an array of arguments oScript.execute( [ oData ] ); // If the script doesn't load } else { // Define text variables for the message sTitle = "Read Error"; sMessage = String( "The '%1' file could not be loaded." ).arg( sScriptPath ); // If the application is showing prompts if( App.showPrompts() ){ // Inform the user MessageBox.information( text( sMessage ), text( sTitle ), sButton ); } // Provide feecback print( sTitle, ":", sMessage ); } // If a script is not found } else { // Define text variables for the message sTitle = text( "File Not Found" ); sMessage = text( "A '%1.ds(a|b|e)' file could not be found." ).arg( sBasePath ); // If the application is showing prompts if( App.showPrompts() ){ // Inform the user MessageBox.information( text( sMessage ), text( sTitle ), sButton ); } // Provide feecback print( sTitle, ":", sMessage ); } // Finalize the function and invoke })();
// Define an anonymous function; // serves as our main loop, // limits the scope of variables (function( aArgs ){ /*********************************************************************/ // String : A function for retrieving a translation if one exists function text( sText ) { // If the version of the application supports qsTr() if( typeof( qsTr ) != "undefined" ){ // Return the translated (if any) text return qsTr( sText ); } // Return the original text return sText; }; /*********************************************************************/ // String : A function for opening the application log function openApplicationLog() { // Cause any data in the log buffer to be written to file App.flushLogBuffer(); // Cause the log file to be shown App.showURL( App.getLogFilename() ); }; /*********************************************************************/ // Construct the message var sMessage = text( "This script accepts exactly 1 argument - an ECMA Object. " + "This Object must define three (3) members, named 'target_path', 'source_paths' " + "and 'relative_paths'. The values of the 'target_path' member must be of " + "the String type and should provide the absolute path of the zlib compressed " + "file (*.zip) to create. The values of the 'source_paths' and 'relative_paths' " + "members must be of the Array type. The 'source_paths' Array should consist " + "of String elements that define the absolute paths of the individual files to " + "include in the file specified by the 'target_path' member. The 'relative_paths' " + "Array should consist of String elements that define the corresponding relative " + "paths of the individual files specified in the 'source_paths' Array, as they " + "should be named/placed within the file specified by the 'target_path' member. " + "An optional fourth member named 'run_silent' of the Boolean type may be " + "defined to control whether or not modal messages to the user are supressed.\n\n" + "Example:\n" + "{\n" + "\t\"target_path\": \"C:/Temp/MyArchive.zip\",\n" + "\t\"source_paths\": [ \"D:/Absolute/Path/To/A/File.ext\" ],\n" + "\t\"relative_paths\": [ \"Path/To/A/File.ext\" ],\n" + "\t\"run_silent\": false\n" + "}" ); var sTitle = text( "Usage" ); var sOk = text( "&OK" ); // Initialize var sTgtPath = ""; var aSrcPaths = []; var aRelPaths = []; var bSilent = false; // Declare working variables var vArg0; var vTarget; var vSrcPaths; var vRelPaths; var vSilent; // If this script was executed remotely with an argument if( aArgs.length > 0 ){ // Get the first argument vArg0 = aArgs[0]; // If it is not an ECMA Object if( typeof( vArg0 ) != "object" ){ // Inform the user MessageBox.information( text( sMessage ), text( sTitle ), sOk ); // We are done... return; } // If it has a member named "target_path" if( vArg0.hasOwnProperty( "target_path" ) ){ // Get the "target_path" value vTarget = vArg0[ "target_path" ]; // If "target_path" is not a string if( typeof( vTarget ) != "string" ){ // Inform the user MessageBox.information( text( sMessage ), text( sTitle ), sOk ); // We are done... return; } // Capture the value sTgtPath = vTarget; // If the value does not end with ".zip" if( !sTgtPath.endsWith( ".zip" ) ){ // Inform the user MessageBox.information( text( sMessage ), text( sTitle ), sOk ); // We are done... return; } } // If it has a member named "source_paths" if( vArg0.hasOwnProperty( "source_paths" ) ){ // Get the "source_paths" value vSrcPaths = vArg0[ "source_paths" ]; // If "source_paths" is not an Array if( !Array.isArray( vSrcPaths ) ){ // Inform the user MessageBox.information( text( sMessage ), text( sTitle ), sOk ); // We are done... return; } // Capture the value aSrcPaths = vSrcPaths; // If the value does not contain entries if( aSrcPaths.length < 1 ){ // Inform the user MessageBox.information( text( sMessage ), text( sTitle ), sOk ); // We are done... return; } } // If it has a member named "relative_paths" if( vArg0.hasOwnProperty( "relative_paths" ) ){ // Get the "relative_paths" value vRelPaths = vArg0[ "relative_paths" ]; // If "relative_paths" is not an Array if( !Array.isArray( vRelPaths ) ){ // Inform the user MessageBox.information( text( sMessage ), text( sTitle ), sOk ); // We are done... return; } // Capture the value aRelPaths = vRelPaths; // If the value does not contain entries if( aRelPaths.length < 1 ){ // Inform the user MessageBox.information( text( sMessage ), text( sTitle ), sOk ); // We are done... return; } } // If it has a member named "run_silent" if( vArg0.hasOwnProperty( "run_silent" ) ){ // Get the "run_silent" value vSilent = vArg0[ "run_silent" ]; // If "run_silent" is not a Boolean if( typeof( vSilent ) != "boolean" ){ // Inform the user MessageBox.information( text( sMessage ), text( sTitle ), sOk ); // We are done... return; } // Capture the value bSilent = vSilent; } } // If the application version is less than 4.9.3.149 if( App.version64 < 0x0004000900030095 ){ // Define our message strings sTitle = "Version Error"; sMessage = String( "This script requires %1 4.9.3.149 or newer to continue." ) .arg( App.appName ) // If prompts are not being supressed if( !bSilent && App.showPrompts() ){ // Inform the user MessageBox.information( text( sMessage ), text( sTitle ), sOk ); } // Provide feecback print( sTitle, ":", sMessage ); // We are done.. return; } // If the length of the source and relative path arrays do not match if( sTgtPath.isEmpty() || aSrcPaths.length < 1 || aSrcPaths.length != aRelPaths.length ){ // If prompts are not being supressed if( !bSilent && App.showPrompts() ){ // Inform the user MessageBox.information( text( sMessage ), text( sTitle ), sOk ); } // Provide feedback print( sTitle, ":", sMessage ); // We are done... return; } // Create a file info object var oFileInfo = new DzFileInfo( sTgtPath ); // Get the absolute path for the target file var sFilePath = oFileInfo.absolutePath(); // Create a directory object var oDir = new DzDir( sFilePath ); // If the directory does not exist if( !oDir.exists() ){ // If we cannot create all the missing directories in the path if( !oDir.mkpath( sFilePath ) ){ // Define the message sTitle = "Resource Error"; sMessage = String( "'%1' could not be created." ).arg( sFilePath ); // If prompts are not being supressed if( !bSilent && App.showPrompts() ){ // Inform the user MessageBox.warning( text( sMessage ), text( sTitle ), sOk ); } // Provide feedback print( sTitle, ":", sMessage ); // We are done... return; } } // Create a zip file object var oZipFile = new DzZipFile( sTgtPath ); // If we cannot open the zip file for writing if( !oZipFile.open( DzZipFile.WriteOnly ) ){ // Define the message sTitle = "Resource Error"; sMessage = String( "'%1' could not be opened for writing." ).arg( sTgtPath ); // If prompts are not being supressed if( !bSilent && App.showPrompts() ){ // Inform the user MessageBox.warning( text( sMessage ), text( sTitle ), sOk ); } // Provide feedback print( sTitle, ":", sMessage ); // We are done... return; } // Declare working variables var sSrcPath; var sRelPath; var aRelFilePath; var sSrcFilePath; var sRelFilePath; // Initialize var bHasFeedback = false; var oFolderMap = {}; // Let the user know we are busy setBusyCursor(); // Create a file info object var oFileInfo = new DzFileInfo( "" ); // Iterate over the paths for( var i = 0, n = aSrcPaths.length; i < n; i += 1 ){ // Get the 'current' source path sSrcFilePath = aSrcPaths[i]; // Get the 'current' relative path sRelFilePath = aRelPaths[i]; // If the relative path starts with a slash if( sRelFilePath[0] == '/' ){ // Provide feedback print( String( "'%1' contains a leading slash." ).arg( sRelFilePath ) ); // Update the feedback flag bHasFeedback = true; // Remove the leading slash sRelFilePath = sRelFilePath.substring( 1 ); } // If the tail of the pair do not match if( sSrcFilePath.toLowerCase().lastIndexOf( sRelFilePath.toLowerCase() ) < 0 ){ // Provide feedback print( String( "'%1' is not relative to '%2'." ).arg( sRelFilePath ).arg( sSrcFilePath ) ); // Update the feedback flag bHasFeedback = true; } // Update the file we are interested in oFileInfo.setFile( sSrcFilePath ); // If the file does not exist if( !oFileInfo.exists() ){ // Provide feedback print( String( "'%1' does not exist." ).arg( sSrcFilePath ) ); // Update the feedback flag bHasFeedback = true; // Next!! continue; } // If the file is not readable if( !oFileInfo.isReadable() ){ // Provide feedback print( String( "'%1' is not readable." ).arg( sSrcFilePath ) ); // Update the feedback flag bHasFeedback = true; // Next!! continue; } // If the file is zero bytes if( oFileInfo.size() < 1 ){ // Provide feedback print( String( "'%1' is zero byte." ).arg( sSrcFilePath ) ); // Update the feedback flag bHasFeedback = true; // Next!! continue; } // Split the relative file path into parts aRelFilePath = sRelFilePath.split( "/" ); // We do not want the filename aRelFilePath.pop(); // Iterate over the path parts for( var j = 0, m = aRelFilePath.length; j < m; j += 1 ){ // Build the relative in-zip path for the 'current' directory sRelPath = aRelFilePath.slice( 0, j + 1 ).join( "/" ) + "/"; // If we have not processed this path yet if( !oFolderMap.hasOwnProperty( sRelPath ) ){ // Get the absolute path for the source directory sSrcPath = oFileInfo.absolutePath() + "/"; // Update our folder map oFolderMap[ sRelPath ] = sSrcPath; // If we cannot add the directory to the zip if( !oZipFile.addDirToZip( sSrcPath, sRelPath ) ){ // Provide feedback print( String( "'%1' could not be added to '%2'." ).arg( sRelPath ).arg( sTgtPath ) ); // Update the feedback flag bHasFeedback = true; } } } // If we cannot add the file to the zip if( !oZipFile.addFileToZip( sSrcFilePath, sRelFilePath ) ){ // Provide feedback print( String( "'%1' could not be added to '%2'." ).arg( sSrcFilePath ).arg( sTgtPath ) ); // Update the feedback flag bHasFeedback = true; } } // Close the zip file oZipFile.close(); // Let the user know we are done clearBusyCursor(); // If there is feedback to be conveyed to the user, // and we are showing prompts if( !bSilent && App.showPrompts() ){ // Define the message sTitle = text( "Execution Compete" ); sMessage = text( "'%1' has been created." ).arg( sTgtPath ); // If there is feedback to provide if( bHasFeedback ){ // Ammend the message sMessage += "\n\n" + text( "Events encountered during the process were written to the application log." ); } // Inform the user switch( MessageBox.information( sMessage, sTitle, sOk, text( "Show..." ), bHasFeedback ? text( "See Log..." ) : "" ) ){ case 1: // Cause the OS file browser to be opened App.showInNativeBrowser( sTgtPath ); break; case 2: // Cause the file to be opened openApplicationLog(); break; default: break } } // Finalize the function and invoke })( getArguments() );