| #!/usr/bin/tclsh |
| # |
| # This script is used to generate a VSIX (Visual Studio Extension) file for |
| # SQLite usable by Visual Studio. |
| # |
| # PREREQUISITES |
| # |
| # 1. Tcl 8.4 and later are supported, earlier versions have not been tested. |
| # |
| # 2. The "sqlite3.h" file is assumed to exist in the parent directory of the |
| # directory containing this script. The [optional] second command line |
| # argument to this script may be used to specify an alternate location. |
| # This script also assumes that the "sqlite3.h" file corresponds with the |
| # version of the binaries to be packaged. This assumption is not verified |
| # by this script. |
| # |
| # 3. The temporary directory specified in the TEMP or TMP environment variables |
| # must refer to an existing directory writable by the current user. |
| # |
| # 4. The "zip" and "unzip" command line tools must be located either in a |
| # directory contained in the PATH environment variable or specified as the |
| # exact file names to execute in the "ZipTool" and "UnZipTool" environment |
| # variables, respectively. |
| # |
| # 5. The template VSIX file (which is basically a zip file) must be located in |
| # a "win" directory inside the directory containing this script. It should |
| # not contain any executable binaries. It should only contain dynamic |
| # textual content files to be processed using [subst] and/or static content |
| # files to be copied verbatim. |
| # |
| # 6. The executable and other compiled binary files to be packaged into the |
| # final VSIX file (e.g. DLLs, LIBs, and PDBs) must be located in a single |
| # directory tree. The top-level directory of the tree must be specified as |
| # the first command line argument to this script. The second level |
| # sub-directory names must match those of the build configuration (e.g. |
| # "Debug" or "Retail"). The third level sub-directory names must match |
| # those of the platform (e.g. "x86", "x64", and "ARM"). For example, the |
| # binary files to be packaged would need to be organized as follows when |
| # packaging the "Debug" and "Retail" build configurations for the "x86" and |
| # "x64" platforms (in this example, "C:\temp" is the top-level directory as |
| # specified in the first command line argument): |
| # |
| # C:\Temp\Debug\x86\sqlite3.lib |
| # C:\Temp\Debug\x86\sqlite3.dll |
| # C:\Temp\Debug\x86\sqlite3.pdb |
| # C:\Temp\Debug\x64\sqlite3.lib |
| # C:\Temp\Debug\x64\sqlite3.dll |
| # C:\Temp\Debug\x64\sqlite3.pdb |
| # C:\Temp\Retail\x86\sqlite3.lib |
| # C:\Temp\Retail\x86\sqlite3.dll |
| # C:\Temp\Retail\x86\sqlite3.pdb |
| # C:\Temp\Retail\x64\sqlite3.lib |
| # C:\Temp\Retail\x64\sqlite3.dll |
| # C:\Temp\Retail\x64\sqlite3.pdb |
| # |
| # The above directory tree organization is performed automatically if the |
| # "tool\build-all-msvc.bat" batch script is used to build the binary files |
| # to be packaged. |
| # |
| # USAGE |
| # |
| # The first argument to this script is required and must be the name of the |
| # top-level directory containing the directories and files organized into a |
| # tree as described in item 6 of the PREREQUISITES section, above. The second |
| # argument is optional and if present must contain the name of the directory |
| # containing the root of the source tree for SQLite. The third argument is |
| # optional and if present must contain the flavor the VSIX package to build. |
| # Currently, the only supported package flavors are "WinRT", "WinRT81", "WP80", |
| # "WP81", and "Win32". The fourth argument is optional and if present must be |
| # a string containing a list of platforms to include in the VSIX package. The |
| # platform list is "platform1,platform2,platform3". The fifth argument is |
| # optional and if present must contain the version of Visual Studio required by |
| # the package. Currently, the only supported versions are "2012" and "2013". |
| # The package flavors "WinRT81" and "WP81" are only supported when the Visual |
| # Studio version is "2013". Typically, when on Windows, this script is |
| # executed using commands similar to the following from a normal Windows |
| # command prompt: |
| # |
| # CD /D C:\dev\sqlite\core |
| # tclsh tool\mkvsix.tcl C:\Temp |
| # |
| # In the example above, "C:\dev\sqlite\core" represents the root of the source |
| # tree for SQLite and "C:\Temp" represents the top-level directory containing |
| # the executable and other compiled binary files, organized into a directory |
| # tree as described in item 6 of the PREREQUISITES section, above. |
| # |
| # This script should work on non-Windows platforms as well, provided that all |
| # the requirements listed in the PREREQUISITES section are met. |
| # |
| # NOTES |
| # |
| # The temporary directory is used as a staging area for the final VSIX file. |
| # The template VSIX file is extracted, its contents processed, and then the |
| # resulting files are packaged into the final VSIX file. |
| # |
| package require Tcl 8.4 |
| |
| proc fail { {error ""} {usage false} } { |
| if {[string length $error] > 0} then { |
| puts stdout $error |
| if {!$usage} then {exit 1} |
| } |
| |
| puts stdout "usage:\ |
| [file tail [info nameofexecutable]]\ |
| [file tail [info script]] <binaryDirectory> \[sourceDirectory\]\ |
| \[packageFlavor\] \[platformNames\] \[vsVersion\]" |
| |
| exit 1 |
| } |
| |
| proc getEnvironmentVariable { name } { |
| # |
| # NOTE: Returns the value of the specified environment variable or an empty |
| # string for environment variables that do not exist in the current |
| # process environment. |
| # |
| return [expr {[info exists ::env($name)] ? $::env($name) : ""}] |
| } |
| |
| proc getTemporaryPath {} { |
| # |
| # NOTE: Returns the normalized path to the first temporary directory found |
| # in the typical set of environment variables used for that purpose |
| # or an empty string to signal a failure to locate such a directory. |
| # |
| set names [list] |
| |
| foreach name [list TEMP TMP] { |
| lappend names [string toupper $name] [string tolower $name] \ |
| [string totitle $name] |
| } |
| |
| foreach name $names { |
| set value [getEnvironmentVariable $name] |
| |
| if {[string length $value] > 0} then { |
| return [file normalize $value] |
| } |
| } |
| |
| return "" |
| } |
| |
| proc appendArgs { args } { |
| # |
| # NOTE: Returns all passed arguments joined together as a single string with |
| # no intervening spaces between arguments. |
| # |
| eval append result $args |
| } |
| |
| proc readFile { fileName } { |
| # |
| # NOTE: Reads and returns the entire contents of the specified file, which |
| # may contain binary data. |
| # |
| set file_id [open $fileName RDONLY] |
| fconfigure $file_id -encoding binary -translation binary |
| set result [read $file_id] |
| close $file_id |
| return $result |
| } |
| |
| proc writeFile { fileName data } { |
| # |
| # NOTE: Writes the entire contents of the specified file, which may contain |
| # binary data. |
| # |
| set file_id [open $fileName {WRONLY CREAT TRUNC}] |
| fconfigure $file_id -encoding binary -translation binary |
| puts -nonewline $file_id $data |
| close $file_id |
| return "" |
| } |
| |
| # |
| # TODO: Modify this procedure when a new version of Visual Studio is released. |
| # |
| proc getMinVsVersionXmlChunk { vsVersion } { |
| switch -exact $vsVersion { |
| 2012 { |
| return [appendArgs \ |
| "\r\n " {MinVSVersion="11.0"}] |
| } |
| 2013 { |
| return [appendArgs \ |
| "\r\n " {MinVSVersion="12.0"}] |
| } |
| 2015 { |
| return [appendArgs \ |
| "\r\n " {MinVSVersion="14.0"}] |
| } |
| default { |
| return "" |
| } |
| } |
| } |
| |
| # |
| # TODO: Modify this procedure when a new version of Visual Studio is released. |
| # |
| proc getMaxPlatformVersionXmlChunk { packageFlavor vsVersion } { |
| # |
| # NOTE: Only Visual Studio 2013 and later support this attribute within the |
| # SDK manifest. |
| # |
| if {![string equal $vsVersion 2013] && \ |
| ![string equal $vsVersion 2015]} then { |
| return "" |
| } |
| |
| switch -exact $packageFlavor { |
| WinRT { |
| return [appendArgs \ |
| "\r\n " {MaxPlatformVersion="8.0"}] |
| } |
| WinRT81 { |
| return [appendArgs \ |
| "\r\n " {MaxPlatformVersion="8.1"}] |
| } |
| WP80 { |
| return [appendArgs \ |
| "\r\n " {MaxPlatformVersion="8.0"}] |
| } |
| WP81 { |
| return [appendArgs \ |
| "\r\n " {MaxPlatformVersion="8.1"}] |
| } |
| default { |
| return "" |
| } |
| } |
| } |
| |
| # |
| # TODO: Modify this procedure when a new version of Visual Studio is released. |
| # |
| proc getExtraFileListXmlChunk { packageFlavor vsVersion } { |
| # |
| # NOTE: Windows Phone 8.0 does not require any extra attributes in its VSIX |
| # package SDK manifests; however, it appears that Windows Phone 8.1 |
| # does. |
| # |
| if {[string equal $packageFlavor WP80]} then { |
| return "" |
| } |
| |
| set appliesTo [expr {[string equal $packageFlavor Win32] ? \ |
| "VisualC" : "WindowsAppContainer"}] |
| |
| switch -exact $vsVersion { |
| 2012 { |
| return [appendArgs \ |
| "\r\n " AppliesTo=\" $appliesTo \" \ |
| "\r\n " {DependsOn="Microsoft.VCLibs, version=11.0"}] |
| } |
| 2013 { |
| return [appendArgs \ |
| "\r\n " AppliesTo=\" $appliesTo \" \ |
| "\r\n " {DependsOn="Microsoft.VCLibs, version=12.0"}] |
| } |
| 2015 { |
| return [appendArgs \ |
| "\r\n " AppliesTo=\" $appliesTo \" \ |
| "\r\n " {DependsOn="Microsoft.VCLibs, version=14.0"}] |
| } |
| default { |
| return "" |
| } |
| } |
| } |
| |
| proc replaceFileNameTokens { fileName name buildName platformName } { |
| # |
| # NOTE: Returns the specified file name containing the platform name instead |
| # of platform placeholder tokens. |
| # |
| return [string map [list <build> $buildName <platform> $platformName \ |
| <name> $name] $fileName] |
| } |
| |
| proc substFile { fileName } { |
| # |
| # NOTE: Performs all Tcl command, variable, and backslash substitutions in |
| # the specified file and then rewrites the contents of that same file |
| # with the substituted data. |
| # |
| return [writeFile $fileName [uplevel 1 [list subst [readFile $fileName]]]] |
| } |
| |
| # |
| # NOTE: This is the entry point for this script. |
| # |
| set script [file normalize [info script]] |
| |
| if {[string length $script] == 0} then { |
| fail "script file currently being evaluated is unknown" true |
| } |
| |
| set path [file dirname $script] |
| set rootName [file rootname [file tail $script]] |
| |
| ############################################################################### |
| |
| # |
| # NOTE: Process and verify all the command line arguments. |
| # |
| set argc [llength $argv] |
| if {$argc < 1 || $argc > 5} then {fail} |
| |
| set binaryDirectory [lindex $argv 0] |
| |
| if {[string length $binaryDirectory] == 0} then { |
| fail "invalid binary directory" |
| } |
| |
| if {![file exists $binaryDirectory] || \ |
| ![file isdirectory $binaryDirectory]} then { |
| fail "binary directory does not exist" |
| } |
| |
| if {$argc >= 2} then { |
| set sourceDirectory [lindex $argv 1] |
| } else { |
| # |
| # NOTE: Assume that the source directory is the parent directory of the one |
| # that contains this script file. |
| # |
| set sourceDirectory [file dirname $path] |
| } |
| |
| if {[string length $sourceDirectory] == 0} then { |
| fail "invalid source directory" |
| } |
| |
| if {![file exists $sourceDirectory] || \ |
| ![file isdirectory $sourceDirectory]} then { |
| fail "source directory does not exist" |
| } |
| |
| if {$argc >= 3} then { |
| set packageFlavor [lindex $argv 2] |
| } else { |
| # |
| # NOTE: Assume the package flavor is WinRT. |
| # |
| set packageFlavor WinRT |
| } |
| |
| if {[string length $packageFlavor] == 0} then { |
| fail "invalid package flavor" |
| } |
| |
| if {$argc >= 4} then { |
| set platformNames [list] |
| |
| foreach platformName [split [lindex $argv 3] ", "] { |
| set platformName [string trim $platformName] |
| |
| if {[string length $platformName] > 0} then { |
| lappend platformNames $platformName |
| } |
| } |
| } |
| |
| if {$argc >= 5} then { |
| set vsVersion [lindex $argv 4] |
| } else { |
| set vsVersion 2012 |
| } |
| |
| if {[string length $vsVersion] == 0} then { |
| fail "invalid Visual Studio version" |
| } |
| |
| if {![string equal $vsVersion 2012] && ![string equal $vsVersion 2013] && \ |
| ![string equal $vsVersion 2015]} then { |
| fail [appendArgs \ |
| "unsupported Visual Studio version, must be one of: " \ |
| [list 2012 2013 2015]] |
| } |
| |
| set shortNames(WinRT,2012) SQLite.WinRT |
| set shortNames(WinRT,2013) SQLite.WinRT.2013 |
| set shortNames(WinRT81,2013) SQLite.WinRT81 |
| set shortNames(WP80,2012) SQLite.WP80 |
| set shortNames(WP80,2013) SQLite.WP80.2013 |
| set shortNames(WP81,2013) SQLite.WP81 |
| set shortNames(Win32,2012) SQLite.Win32 |
| set shortNames(Win32,2013) SQLite.Win32.2013 |
| set shortNames(UWP,2015) SQLite.UWP.2015 |
| |
| set displayNames(WinRT,2012) "SQLite for Windows Runtime" |
| set displayNames(WinRT,2013) "SQLite for Windows Runtime" |
| set displayNames(WinRT81,2013) "SQLite for Windows Runtime (Windows 8.1)" |
| set displayNames(WP80,2012) "SQLite for Windows Phone" |
| set displayNames(WP80,2013) "SQLite for Windows Phone" |
| set displayNames(WP81,2013) "SQLite for Windows Phone 8.1" |
| set displayNames(Win32,2012) "SQLite for Windows" |
| set displayNames(Win32,2013) "SQLite for Windows" |
| set displayNames(UWP,2015) "SQLite for Universal Windows Platform" |
| |
| if {[string equal $packageFlavor WinRT]} then { |
| set shortName $shortNames($packageFlavor,$vsVersion) |
| set displayName $displayNames($packageFlavor,$vsVersion) |
| set targetPlatformIdentifier Windows |
| set targetPlatformVersion v8.0 |
| set minVsVersion [getMinVsVersionXmlChunk $vsVersion] |
| set maxPlatformVersion \ |
| [getMaxPlatformVersionXmlChunk $packageFlavor $vsVersion] |
| set extraSdkPath "" |
| set extraFileListAttributes \ |
| [getExtraFileListXmlChunk $packageFlavor $vsVersion] |
| } elseif {[string equal $packageFlavor WinRT81]} then { |
| if {$vsVersion ne "2013"} then { |
| fail [appendArgs \ |
| "unsupported combination, package flavor " $packageFlavor \ |
| " is only supported with Visual Studio 2013"] |
| } |
| set shortName $shortNames($packageFlavor,$vsVersion) |
| set displayName $displayNames($packageFlavor,$vsVersion) |
| set targetPlatformIdentifier Windows |
| set targetPlatformVersion v8.1 |
| set minVsVersion [getMinVsVersionXmlChunk $vsVersion] |
| set maxPlatformVersion \ |
| [getMaxPlatformVersionXmlChunk $packageFlavor $vsVersion] |
| set extraSdkPath "" |
| set extraFileListAttributes \ |
| [getExtraFileListXmlChunk $packageFlavor $vsVersion] |
| } elseif {[string equal $packageFlavor WP80]} then { |
| set shortName $shortNames($packageFlavor,$vsVersion) |
| set displayName $displayNames($packageFlavor,$vsVersion) |
| set targetPlatformIdentifier "Windows Phone" |
| set targetPlatformVersion v8.0 |
| set minVsVersion [getMinVsVersionXmlChunk $vsVersion] |
| set maxPlatformVersion \ |
| [getMaxPlatformVersionXmlChunk $packageFlavor $vsVersion] |
| set extraSdkPath "\\..\\$targetPlatformIdentifier" |
| set extraFileListAttributes \ |
| [getExtraFileListXmlChunk $packageFlavor $vsVersion] |
| } elseif {[string equal $packageFlavor WP81]} then { |
| if {$vsVersion ne "2013"} then { |
| fail [appendArgs \ |
| "unsupported combination, package flavor " $packageFlavor \ |
| " is only supported with Visual Studio 2013"] |
| } |
| set shortName $shortNames($packageFlavor,$vsVersion) |
| set displayName $displayNames($packageFlavor,$vsVersion) |
| set targetPlatformIdentifier WindowsPhoneApp |
| set targetPlatformVersion v8.1 |
| set minVsVersion [getMinVsVersionXmlChunk $vsVersion] |
| set maxPlatformVersion \ |
| [getMaxPlatformVersionXmlChunk $packageFlavor $vsVersion] |
| set extraSdkPath "\\..\\$targetPlatformIdentifier" |
| set extraFileListAttributes \ |
| [getExtraFileListXmlChunk $packageFlavor $vsVersion] |
| } elseif {[string equal $packageFlavor UWP]} then { |
| if {$vsVersion ne "2015"} then { |
| fail [appendArgs \ |
| "unsupported combination, package flavor " $packageFlavor \ |
| " is only supported with Visual Studio 2015"] |
| } |
| set shortName $shortNames($packageFlavor,$vsVersion) |
| set displayName $displayNames($packageFlavor,$vsVersion) |
| set targetPlatformIdentifier UAP; # NOTE: Not "UWP". |
| set targetPlatformVersion v0.8.0.0 |
| set minVsVersion [getMinVsVersionXmlChunk $vsVersion] |
| set maxPlatformVersion \ |
| [getMaxPlatformVersionXmlChunk $packageFlavor $vsVersion] |
| set extraSdkPath "\\..\\$targetPlatformIdentifier" |
| set extraFileListAttributes \ |
| [getExtraFileListXmlChunk $packageFlavor $vsVersion] |
| } elseif {[string equal $packageFlavor Win32]} then { |
| set shortName $shortNames($packageFlavor,$vsVersion) |
| set displayName $displayNames($packageFlavor,$vsVersion) |
| set targetPlatformIdentifier Windows |
| set targetPlatformVersion v8.0 |
| set minVsVersion [getMinVsVersionXmlChunk $vsVersion] |
| set maxPlatformVersion \ |
| [getMaxPlatformVersionXmlChunk $packageFlavor $vsVersion] |
| set extraSdkPath "" |
| set extraFileListAttributes \ |
| [getExtraFileListXmlChunk $packageFlavor $vsVersion] |
| } else { |
| fail [appendArgs \ |
| "unsupported package flavor, must be one of: " \ |
| [list WinRT WinRT81 WP80 WP81 UWP Win32]] |
| } |
| |
| ############################################################################### |
| |
| # |
| # NOTE: Evaluate the user-specific customizations file, if it exists. |
| # |
| set userFile [file join $path [appendArgs \ |
| $rootName . $tcl_platform(user) .tcl]] |
| |
| if {[file exists $userFile] && \ |
| [file isfile $userFile]} then { |
| source $userFile |
| } |
| |
| ############################################################################### |
| |
| set templateFile [file join $path win sqlite.vsix] |
| |
| if {![file exists $templateFile] || \ |
| ![file isfile $templateFile]} then { |
| fail [appendArgs "template file \"" $templateFile "\" does not exist"] |
| } |
| |
| set currentDirectory [pwd] |
| set outputFile [file join $currentDirectory [appendArgs sqlite- \ |
| $packageFlavor -output.vsix]] |
| |
| if {[file exists $outputFile]} then { |
| fail [appendArgs "output file \"" $outputFile "\" already exists"] |
| } |
| |
| ############################################################################### |
| |
| # |
| # NOTE: Make sure that a valid temporary directory exists. |
| # |
| set temporaryDirectory [getTemporaryPath] |
| |
| if {[string length $temporaryDirectory] == 0 || \ |
| ![file exists $temporaryDirectory] || \ |
| ![file isdirectory $temporaryDirectory]} then { |
| fail "cannot locate a usable temporary directory" |
| } |
| |
| # |
| # NOTE: Setup the staging directory to have a unique name inside of the |
| # configured temporary directory. |
| # |
| set stagingDirectory [file normalize [file join $temporaryDirectory \ |
| [appendArgs $rootName . [pid]]]] |
| |
| ############################################################################### |
| |
| # |
| # NOTE: Configure the external zipping tool. First, see if it has already |
| # been pre-configured. If not, try to query it from the environment. |
| # Finally, fallback on the default of simply "zip", which will then |
| # be assumed to exist somewhere along the PATH. |
| # |
| if {![info exists zip]} then { |
| if {[info exists env(ZipTool)]} then { |
| set zip $env(ZipTool) |
| } |
| if {![info exists zip] || ![file exists $zip]} then { |
| set zip zip |
| } |
| } |
| |
| # |
| # NOTE: Configure the external unzipping tool. First, see if it has already |
| # been pre-configured. If not, try to query it from the environment. |
| # Finally, fallback on the default of simply "unzip", which will then |
| # be assumed to exist somewhere along the PATH. |
| # |
| if {![info exists unzip]} then { |
| if {[info exists env(UnZipTool)]} then { |
| set unzip $env(UnZipTool) |
| } |
| if {![info exists unzip] || ![file exists $unzip]} then { |
| set unzip unzip |
| } |
| } |
| |
| ############################################################################### |
| |
| # |
| # NOTE: Attempt to extract the SQLite version from the "sqlite3.h" header file |
| # in the source directory. This script assumes that the header file has |
| # already been generated by the build process. |
| # |
| set pattern {^#define\s+SQLITE_VERSION\s+"(.*)"$} |
| set data [readFile [file join $sourceDirectory sqlite3.h]] |
| |
| if {![regexp -line -- $pattern $data dummy version]} then { |
| fail [appendArgs "cannot locate SQLITE_VERSION value in \"" \ |
| [file join $sourceDirectory sqlite3.h] \"] |
| } |
| |
| ############################################################################### |
| |
| # |
| # NOTE: Setup all the master file list data. This includes the source file |
| # names, the destination file names, and the file processing flags. The |
| # possible file processing flags are: |
| # |
| # "buildNeutral" -- This flag indicates the file location and content do |
| # not depend on the build configuration. |
| # |
| # "platformNeutral" -- This flag indicates the file location and content |
| # do not depend on the build platform. |
| # |
| # "subst" -- This flag indicates that the file contains dynamic textual |
| # content that needs to be processed using [subst] prior to |
| # packaging the file into the final VSIX package. The primary |
| # use of this flag is to insert the name of the VSIX package, |
| # some package flavor-specific value, or the SQLite version |
| # into a file. |
| # |
| # "noDebug" -- This flag indicates that the file should be skipped when |
| # processing the debug build. |
| # |
| # "noRetail" -- This flag indicates that the file should be skipped when |
| # processing the retail build. |
| # |
| # "move" -- This flag indicates that the file should be moved from the |
| # source to the destination instead of being copied. |
| # |
| # This file metadata may be overridden, either in whole or in part, via |
| # the user-specific customizations file. |
| # |
| if {![info exists fileNames(source)]} then { |
| set fileNames(source) [list "" "" \ |
| [file join $stagingDirectory DesignTime <build> <platform> sqlite3.props] \ |
| [file join $sourceDirectory sqlite3.h] \ |
| [file join $binaryDirectory <build> <platform> sqlite3.lib] \ |
| [file join $binaryDirectory <build> <platform> sqlite3.dll]] |
| |
| if {![info exists no(symbols)]} then { |
| lappend fileNames(source) \ |
| [file join $binaryDirectory <build> <platform> sqlite3.pdb] |
| } |
| } |
| |
| if {![info exists fileNames(destination)]} then { |
| set fileNames(destination) [list \ |
| [file join $stagingDirectory extension.vsixmanifest] \ |
| [file join $stagingDirectory SDKManifest.xml] \ |
| [file join $stagingDirectory DesignTime <build> <platform> <name>.props] \ |
| [file join $stagingDirectory DesignTime <build> <platform> sqlite3.h] \ |
| [file join $stagingDirectory DesignTime <build> <platform> sqlite3.lib] \ |
| [file join $stagingDirectory Redist <build> <platform> sqlite3.dll]] |
| |
| if {![info exists no(symbols)]} then { |
| lappend fileNames(destination) \ |
| [file join $stagingDirectory Redist <build> <platform> sqlite3.pdb] |
| } |
| } |
| |
| if {![info exists fileNames(flags)]} then { |
| set fileNames(flags) [list \ |
| [list buildNeutral platformNeutral subst] \ |
| [list buildNeutral platformNeutral subst] \ |
| [list buildNeutral platformNeutral subst move] \ |
| [list buildNeutral platformNeutral] \ |
| [list] [list] [list noRetail]] |
| |
| if {![info exists no(symbols)]} then { |
| lappend fileNames(flags) [list noRetail] |
| } |
| } |
| |
| ############################################################################### |
| |
| # |
| # NOTE: Setup the list of builds supported by this script. These may be |
| # overridden via the user-specific customizations file. |
| # |
| if {![info exists buildNames]} then { |
| set buildNames [list Debug Retail] |
| } |
| |
| ############################################################################### |
| |
| # |
| # NOTE: Setup the list of platforms supported by this script. These may be |
| # overridden via the command line or the user-specific customizations |
| # file. |
| # |
| if {![info exists platformNames] || [llength $platformNames] == 0} then { |
| set platformNames [list x86 x64 ARM] |
| } |
| |
| ############################################################################### |
| |
| # |
| # NOTE: Make sure the staging directory exists, creating it if necessary. |
| # |
| file mkdir $stagingDirectory |
| |
| # |
| # NOTE: Build the Tcl command used to extract the template VSIX package to |
| # the staging directory. |
| # |
| set extractCommand [list exec -- $unzip $templateFile -d $stagingDirectory] |
| |
| # |
| # NOTE: Extract the template VSIX package to the staging directory. |
| # |
| eval $extractCommand |
| |
| ############################################################################### |
| |
| # |
| # NOTE: Process each file in the master file list. There are actually three |
| # parallel lists that contain the source file names, the destination file |
| # names, and the file processing flags. If the "buildNeutral" flag is |
| # present, the file location and content do not depend on the build |
| # configuration and "CommonConfiguration" will be used in place of the |
| # build configuration name. If the "platformNeutral" flag is present, |
| # the file location and content do not depend on the build platform and |
| # "neutral" will be used in place of the build platform name. If the |
| # "subst" flag is present, the file is assumed to be a text file that may |
| # contain Tcl variable, command, and backslash replacements, to be |
| # dynamically replaced during processing using the Tcl [subst] command. |
| # If the "noDebug" flag is present, the file will be skipped when |
| # processing for the debug build. If the "noRetail" flag is present, the |
| # file will be skipped when processing for the retail build. If the |
| # "move" flag is present, the source file will be deleted after it is |
| # copied to the destination file. If the source file name is an empty |
| # string, the destination file name will be assumed to already exist in |
| # the staging directory and will not be copied; however, Tcl variable, |
| # command, and backslash replacements may still be performed on the |
| # destination file prior to the final VSIX package being built if the |
| # "subst" flag is present. |
| # |
| foreach sourceFileName $fileNames(source) \ |
| destinationFileName $fileNames(destination) \ |
| fileFlags $fileNames(flags) { |
| # |
| # NOTE: Process the file flags into separate boolean variables that may be |
| # used within the loop. |
| # |
| set isBuildNeutral [expr {[lsearch $fileFlags buildNeutral] != -1}] |
| set isPlatformNeutral [expr {[lsearch $fileFlags platformNeutral] != -1}] |
| set isMove [expr {[lsearch $fileFlags move] != -1}] |
| set useSubst [expr {[lsearch $fileFlags subst] != -1}] |
| |
| # |
| # NOTE: If the current file is build-neutral, then only one build will |
| # be processed for it, namely "CommonConfiguration"; otherwise, each |
| # supported build will be processed for it individually. |
| # |
| foreach buildName \ |
| [expr {$isBuildNeutral ? [list CommonConfiguration] : $buildNames}] { |
| # |
| # NOTE: Should the current file be skipped for this build? |
| # |
| if {[lsearch $fileFlags no${buildName}] != -1} then { |
| continue |
| } |
| |
| # |
| # NOTE: If the current file is platform-neutral, then only one platform |
| # will be processed for it, namely "neutral"; otherwise, each |
| # supported platform will be processed for it individually. |
| # |
| foreach platformName \ |
| [expr {$isPlatformNeutral ? [list neutral] : $platformNames}] { |
| # |
| # NOTE: Use the actual platform name in the destination file name. |
| # |
| set newDestinationFileName [replaceFileNameTokens $destinationFileName \ |
| $shortName $buildName $platformName] |
| |
| # |
| # NOTE: Does the source file need to be copied to the destination file? |
| # |
| if {[string length $sourceFileName] > 0} then { |
| # |
| # NOTE: First, make sure the destination directory exists. |
| # |
| file mkdir [file dirname $newDestinationFileName] |
| |
| # |
| # NOTE: Then, copy the source file to the destination file verbatim. |
| # |
| set newSourceFileName [replaceFileNameTokens $sourceFileName \ |
| $shortName $buildName $platformName] |
| |
| file copy $newSourceFileName $newDestinationFileName |
| |
| # |
| # NOTE: If this is a move instead of a copy, delete the source file |
| # now. |
| # |
| if {$isMove} then { |
| file delete $newSourceFileName |
| } |
| } |
| |
| # |
| # NOTE: Does the destination file contain dynamic replacements that must |
| # be processed now? |
| # |
| if {$useSubst} then { |
| # |
| # NOTE: Perform any dynamic replacements contained in the destination |
| # file and then re-write it in-place. |
| # |
| substFile $newDestinationFileName |
| } |
| } |
| } |
| } |
| |
| ############################################################################### |
| |
| # |
| # NOTE: Change the current directory to the staging directory so that the |
| # external archive building tool can pickup the necessary files using |
| # relative paths. |
| # |
| cd $stagingDirectory |
| |
| # |
| # NOTE: Build the Tcl command used to archive the final VSIX package in the |
| # output directory. |
| # |
| set archiveCommand [list exec -- $zip -r $outputFile *] |
| |
| # |
| # NOTE: Build the final VSIX package archive in the output directory. |
| # |
| eval $archiveCommand |
| |
| # |
| # NOTE: Change back to the previously saved current directory. |
| # |
| cd $currentDirectory |
| |
| # |
| # NOTE: Cleanup the temporary staging directory. |
| # |
| file delete -force $stagingDirectory |
| |
| ############################################################################### |
| |
| # |
| # NOTE: Success, emit the fully qualified path of the generated VSIX file. |
| # |
| puts stdout $outputFile |