1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Add tool capable of downloading a TclKit (and its associated SDK) on Windows.

FossilOrigin-Name: 50673ddaf813335777673fa8585997a7551e5323
This commit is contained in:
mistachkin
2015-10-09 17:36:06 +00:00
parent 48cc9a31e1
commit 80372ae248
4 changed files with 707 additions and 7 deletions

View File

@@ -1,5 +1,5 @@
C Convert\sthe\stool/tostr.awk\sscript\sinto\stool/tostr.tcl.\s\sRemove\stwo\sobsolete\nMakefiles.\s\sPurge\sNAWK\sfrom\sthe\sconfigure\sscript\sand\sfrom\sunix\smakefiles.\nThere\sare\sstill\stwo\suses\sof\sNAWK\sin\sMakefile.msc.
D 2015-10-07T12:36:42.935
C Add\stool\scapable\sof\sdownloading\sa\sTclKit\s(and\sits\sassociated\sSDK)\son\sWindows.
D 2015-10-09T17:36:06.162
F Makefile.in 2a247c733c2dd6fab703df04dd009b26413956f5
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 17ce18bb7e9ca2ad3abed9b0a1fcbef3fbe8f307
@@ -1331,6 +1331,8 @@ F test/without_rowid6.test 1f99644e6508447fb050f73697350c7ceca3392e
F test/wordcount.c 9915e06cb33d8ca8109b8700791afe80d305afda
F test/zeroblob.test 3857870fe681b8185654414a9bccfde80b62a0fa
F test/zerodamage.test cf6748bad89553cc1632be51a6f54e487e4039ac
F tool/GetFile.cs 963f7064b0b221b08feadb28894c3537916261ac
F tool/GetTclKit.bat 46092b151f7bb4f2a2735dfa1ada09736a4b35a4
F tool/addopcodes.tcl 7cc82ecca456a6b3148abf492b0419b83140881a
F tool/build-all-msvc.bat 761d8c82a1a529261291812732a853a1b4256d85 x
F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367
@@ -1387,7 +1389,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 8bbf37142ef2759274668f6da114b5c8072e42db
R 07b752064456f02ed0865632d443e697
U drh
Z 7087d810f3111cb2f52748462bb8f6e3
P 5b6775215327a89232f5059653747a18e83b8b4b
R 785a6cb71a38ff7702fb9be84ec0066b
U mistachkin
Z 9f18b94f6375bd392631336361a9d038

View File

@@ -1 +1 @@
5b6775215327a89232f5059653747a18e83b8b4b
50673ddaf813335777673fa8585997a7551e5323

450
tool/GetFile.cs Normal file
View File

@@ -0,0 +1,450 @@
/*
** 2015 October 7
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C# code to download a single file based on a URI.
*/
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
///////////////////////////////////////////////////////////////////////////////
#region Assembly Metadata
[assembly: AssemblyTitle("GetFile Tool")]
[assembly: AssemblyDescription("Download a single file based on a URI.")]
[assembly: AssemblyCompany("SQLite Development Team")]
[assembly: AssemblyProduct("SQLite")]
[assembly: AssemblyCopyright("Public Domain")]
[assembly: ComVisible(false)]
[assembly: Guid("5c4b3728-1693-4a33-a218-8e6973ca15a6")]
[assembly: AssemblyVersion("1.0.*")]
#if DEBUG
[assembly: AssemblyConfiguration("Debug")]
#else
[assembly: AssemblyConfiguration("Release")]
#endif
#endregion
///////////////////////////////////////////////////////////////////////////////
namespace GetFile
{
/// <summary>
/// This enumeration is used to represent all the possible exit codes from
/// this tool.
/// </summary>
internal enum ExitCode
{
/// <summary>
/// The file download was a success.
/// </summary>
Success = 0,
/// <summary>
/// The command line arguments are missing (i.e. null). Generally,
/// this should not happen.
/// </summary>
MissingArgs = 1,
/// <summary>
/// The wrong number of command line arguments was supplied.
/// </summary>
WrongNumArgs = 2,
/// <summary>
/// The URI specified on the command line could not be parsed as a
/// supported absolute URI.
/// </summary>
BadUri = 3,
/// <summary>
/// The file name portion of the URI specified on the command line
/// could not be extracted from it.
/// </summary>
BadFileName = 4,
/// <summary>
/// The temporary directory is either invalid (i.e. null) or does not
/// represent an available directory.
/// </summary>
BadTempPath = 5,
/// <summary>
/// An exception was caught in <see cref="Main" />. Generally, this
/// should not happen.
/// </summary>
Exception = 6,
/// <summary>
/// The file download was canceled. This tool does not make use of
/// the <see cref="WebClient.CancelAsync" /> method; therefore, this
/// should not happen.
/// </summary>
DownloadCanceled = 7,
/// <summary>
/// The file download encountered an error. Further information about
/// this error should be displayed on the console.
/// </summary>
DownloadError = 8
}
///////////////////////////////////////////////////////////////////////////
internal static class Program
{
#region Private Data
/// <summary>
/// This is used to synchronize multithreaded access to the
/// <see cref="previousPercent" /> and <see cref="exitCode"/>
/// fields.
/// </summary>
private static readonly object syncRoot = new object();
///////////////////////////////////////////////////////////////////////
/// <summary>
/// This event will be signed when the file download has completed,
/// even if the file download itself was canceled or unsuccessful.
/// </summary>
private static EventWaitHandle doneEvent;
///////////////////////////////////////////////////////////////////////
/// <summary>
/// The previous file download completion percentage seen by the
/// <see cref="DownloadProgressChanged" /> event handler. This value
/// is never decreased, nor is it ever reset to zero.
/// </summary>
private static int previousPercent = 0;
///////////////////////////////////////////////////////////////////////
/// <summary>
/// This will be the exit code returned by this tool after the file
/// download completes, successfully or otherwise. This value is only
/// changed by the <see cref="DownloadFileCompleted" /> event handler.
/// </summary>
private static ExitCode exitCode = ExitCode.Success;
#endregion
///////////////////////////////////////////////////////////////////////
#region Private Support Methods
/// <summary>
/// This method displays an error message to the console and/or
/// displays the command line usage information for this tool.
/// </summary>
/// <param name="message">
/// The error message to display, if any.
/// </param>
/// <param name="usage">
/// Non-zero to display the command line usage information.
/// </param>
private static void Error(
string message,
bool usage
)
{
if (message != null)
Console.WriteLine(message);
string fileName = Path.GetFileName(
Process.GetCurrentProcess().MainModule.FileName);
Console.WriteLine(String.Format("usage: {0} <uri>", fileName));
}
///////////////////////////////////////////////////////////////////////
/// <summary>
/// This method attempts to determine the file name portion of the
/// specified URI.
/// </summary>
/// <param name="uri">
/// The URI to process.
/// </param>
/// <returns>
/// The file name portion of the specified URI -OR- null if it cannot
/// be determined.
/// </returns>
private static string GetFileName(
Uri uri
)
{
if (uri == null)
return null;
string pathAndQuery = uri.PathAndQuery;
if (String.IsNullOrEmpty(pathAndQuery))
return null;
int index = pathAndQuery.LastIndexOf('/');
if ((index < 0) || (index == pathAndQuery.Length))
return null;
return pathAndQuery.Substring(index + 1);
}
#endregion
///////////////////////////////////////////////////////////////////////
#region Private Event Handlers
/// <summary>
/// This method is an event handler that is called when the file
/// download completion percentage changes. It will display progress
/// on the console. Special care is taken to make sure that progress
/// events are not displayed out-of-order, even if duplicate and/or
/// out-of-order events are received.
/// </summary>
/// <param name="sender">
/// The source of the event.
/// </param>
/// <param name="e">
/// Information for the event being processed.
/// </param>
private static void DownloadProgressChanged(
object sender,
DownloadProgressChangedEventArgs e
)
{
if (e != null)
{
int percent = e.ProgressPercentage;
lock (syncRoot)
{
if (percent > previousPercent)
{
Console.Write('.');
if ((percent % 10) == 0)
Console.Write(" {0}% ", percent);
previousPercent = percent;
}
}
}
}
///////////////////////////////////////////////////////////////////////
/// <summary>
/// This method is an event handler that is called when the file
/// download has completed, successfully or otherwise. It will
/// display the overall result of the file download on the console,
/// including any <see cref="Exception" /> information, if applicable.
/// The <see cref="exitCode" /> field is changed by this method to
/// indicate the overall result of the file download and the event
/// within the <see cref="doneEvent" /> field will be signaled.
/// </summary>
/// <param name="sender">
/// The source of the event.
/// </param>
/// <param name="e">
/// Information for the event being processed.
/// </param>
private static void DownloadFileCompleted(
object sender,
AsyncCompletedEventArgs e
)
{
if (e != null)
{
lock (syncRoot)
{
if (previousPercent < 100)
Console.Write(' ');
}
if (e.Cancelled)
{
Console.WriteLine("Canceled");
lock (syncRoot)
{
exitCode = ExitCode.DownloadCanceled;
}
}
else
{
Exception error = e.Error;
if (error != null)
{
Console.WriteLine("Error: {0}", error);
lock (syncRoot)
{
exitCode = ExitCode.DownloadError;
}
}
else
{
Console.WriteLine("Done");
}
}
}
if (doneEvent != null)
doneEvent.Set();
}
#endregion
///////////////////////////////////////////////////////////////////////
#region Program Entry Point
/// <summary>
/// This is the entry-point for this tool. It handles processing the
/// command line arguments, setting up the web client, downloading the
/// file, and saving it to the file system.
/// </summary>
/// <param name="args">
/// The command line arguments.
/// </param>
/// <returns>
/// Zero upon success; non-zero on failure. This will be one of the
/// values from the <see cref="ExitCode" /> enumeration.
/// </returns>
private static int Main(
string[] args
)
{
//
// NOTE: Sanity check the command line arguments.
//
if (args == null)
{
Error(null, true);
return (int)ExitCode.MissingArgs;
}
if (args.Length != 1)
{
Error(null, true);
return (int)ExitCode.WrongNumArgs;
}
//
// NOTE: Attempt to convert the first (and only) command line
// argument to an absolute URI.
//
Uri uri;
if (!Uri.TryCreate(args[0], UriKind.Absolute, out uri))
{
Error("First argument is not an absolute URI.", false);
return (int)ExitCode.BadUri;
}
//
// NOTE: Attempt to extract the file name portion of the URI we
// just created.
//
string fileName = GetFileName(uri);
if (fileName == null)
{
Error("Could not extract the file name from the URI.", false);
return (int)ExitCode.BadFileName;
}
//
// NOTE: Grab the temporary path setup for this process. If it is
// unavailable, we will not continue.
//
string directory = Path.GetTempPath();
if (String.IsNullOrEmpty(directory) ||
!Directory.Exists(directory))
{
Error("Temporary directory is invalid or unavailable.", false);
return (int)ExitCode.BadTempPath;
}
try
{
using (WebClient webClient = new WebClient())
{
//
// NOTE: Create the event used to signal completion of the
// file download.
//
doneEvent = new ManualResetEvent(false);
//
// NOTE: Hookup the event handlers we care about on the web
// client. These are necessary because the file is
// downloaded asynchronously.
//
webClient.DownloadProgressChanged +=
new DownloadProgressChangedEventHandler(
DownloadProgressChanged);
webClient.DownloadFileCompleted +=
new AsyncCompletedEventHandler(
DownloadFileCompleted);
//
// NOTE: Build the fully qualified path and file name,
// within the temporary directory, where the file to
// be downloaded will be saved.
//
fileName = Path.Combine(directory, fileName);
//
// NOTE: If the file name already exists (in the temporary)
// directory, delete it.
//
// TODO: Perhaps an error should be raised here instead?
//
if (File.Exists(fileName))
File.Delete(fileName);
//
// NOTE: After kicking off the asynchronous file download
// process, wait [forever] until the "done" event is
// signaled.
//
Console.WriteLine(
"Downloading \"{0}\" to \"{1}\"...", uri, fileName);
webClient.DownloadFileAsync(uri, fileName);
doneEvent.WaitOne();
}
lock (syncRoot)
{
return (int)exitCode;
}
}
catch (Exception e)
{
//
// NOTE: An exception was caught. Report it via the console
// and return failure.
//
Error(e.ToString(), false);
return (int)ExitCode.Exception;
}
}
#endregion
}
}

248
tool/GetTclKit.bat Normal file
View File

@@ -0,0 +1,248 @@
@ECHO OFF
::
:: GetTclKit.bat --
::
:: TclKit Download Tool
::
SETLOCAL
REM SET __ECHO=ECHO
REM SET __ECHO2=ECHO
REM SET __ECHO3=ECHO
IF NOT DEFINED _AECHO (SET _AECHO=REM)
IF NOT DEFINED _CECHO (SET _CECHO=REM)
IF NOT DEFINED _VECHO (SET _VECHO=REM)
SET OVERWRITE=^>
IF DEFINED __ECHO SET OVERWRITE=^^^>
SET APPEND=^>^>
IF DEFINED __ECHO SET APPEND=^^^>^^^>
SET PROCESSOR=%1
IF DEFINED PROCESSOR (
CALL :fn_UnquoteVariable PROCESSOR
) ELSE (
GOTO usage
)
%_VECHO% Processor = '%PROCESSOR%'
SET DUMMY2=%2
IF DEFINED DUMMY2 (
GOTO usage
)
SET ROOT=%~dp0\..
SET ROOT=%ROOT:\\=\%
%_VECHO% Root = '%ROOT%'
SET TOOLS=%~dp0
SET TOOLS=%TOOLS:~0,-1%
%_VECHO% Tools = '%TOOLS%'
IF NOT DEFINED windir (
ECHO The windir environment variable must be set first.
GOTO errors
)
%_VECHO% WinDir = '%windir%'
IF NOT DEFINED TEMP (
ECHO The TEMP environment variable must be set first.
GOTO errors
)
%_VECHO% Temp = '%TEMP%'
SET TCLKIT_URI=http://tclsh.com/
%_VECHO% TclKitUri = '%TCLKIT_URI%'
IF /I "%PROCESSOR%" == "x86" (
CALL :fn_TclKitX86Variables
) ELSE IF /I "%PROCESSOR%" == "x64" (
CALL :fn_TclKitX64Variables
) ELSE (
GOTO usage
)
%_VECHO% TclKitPatchLevel = '%TCLKIT_PATCHLEVEL%'
%_VECHO% TclKitNoSdk = '%TCLKIT_NOSDK%'
%_VECHO% TclKitExe = '%TCLKIT_EXE%'
%_VECHO% TclKitLib = '%TCLKIT_LIB%'
%_VECHO% TclKitSdk = '%TCLKIT_SDK%'
%_VECHO% TclKitSdkZip = '%TCLKIT_SDK_ZIP%'
%_VECHO% TclKitFiles = '%TCLKIT_FILES%'
CALL :fn_ResetErrorLevel
FOR %%T IN (csc.exe) DO (
SET %%T_PATH=%%~dp$PATH:T
)
%_VECHO% Csc.exe_PATH = '%csc.exe_PATH%'
IF DEFINED csc.exe_PATH (
GOTO skip_addToPath
)
IF DEFINED FRAMEWORKDIR (
REM Use the existing .NET Framework directory...
) ELSE IF EXIST "%windir%\Microsoft.NET\Framework64\v2.0.50727" (
SET FRAMEWORKDIR=%windir%\Microsoft.NET\Framework64\v2.0.50727
) ELSE IF EXIST "%windir%\Microsoft.NET\Framework64\v3.5" (
SET FRAMEWORKDIR=%windir%\Microsoft.NET\Framework64\v3.5
) ELSE IF EXIST "%windir%\Microsoft.NET\Framework64\v4.0.30319" (
SET FRAMEWORKDIR=%windir%\Microsoft.NET\Framework64\v4.0.30319
) ELSE IF EXIST "%windir%\Microsoft.NET\Framework\v2.0.50727" (
SET FRAMEWORKDIR=%windir%\Microsoft.NET\Framework\v2.0.50727
) ELSE IF EXIST "%windir%\Microsoft.NET\Framework\v3.5" (
SET FRAMEWORKDIR=%windir%\Microsoft.NET\Framework\v3.5
) ELSE IF EXIST "%windir%\Microsoft.NET\Framework\v4.0.30319" (
SET FRAMEWORKDIR=%windir%\Microsoft.NET\Framework\v4.0.30319
) ELSE (
ECHO No suitable version of the .NET Framework appears to be installed.
GOTO errors
)
%_VECHO% FrameworkDir = '%FRAMEWORKDIR%'
IF NOT EXIST "%FRAMEWORKDIR%\csc.exe" (
ECHO The file "%FRAMEWORKDIR%\csc.exe" is missing.
GOTO errors
)
SET PATH=%FRAMEWORKDIR%;%PATH%
:skip_addToPath
%__ECHO% csc.exe "/out:%TEMP%\GetFile.exe" /target:exe "%TOOLS%\GetFile.cs"
IF ERRORLEVEL 1 (
ECHO Compilation of "%TOOLS%\GetFile.cs" failed.
GOTO errors
)
FOR %%F IN (%TCLKIT_FILES%) DO (
IF NOT EXIST "%%F" (
%__ECHO% "%TEMP%\GetFile.exe" "%TCLKIT_URI%%%F"
IF ERRORLEVEL 1 (
ECHO Download of "%%F" from "%TCLKIT_URI%" failed.
GOTO errors
)
)
)
IF DEFINED TCLKIT_NOSDK GOTO skip_sdkUnZip
IF NOT EXIST "%TEMP%\%TCLKIT_SDK%" (
%__ECHO% MKDIR "%TEMP%\%TCLKIT_SDK%"
IF ERRORLEVEL 1 (
ECHO Could not create directory "%TEMP%\%TCLKIT_SDK%".
GOTO errors
)
)
%__ECHO% "%TEMP%\unzip.exe" -o "%TEMP%\%TCLKIT_SDK_ZIP%" -d "%TEMP%\%TCLKIT_SDK%"
IF ERRORLEVEL 1 (
ECHO Could not unzip "%TEMP%\%TCLKIT_SDK_ZIP%" to "%TEMP%\%TCLKIT_SDK%".
GOTO errors
)
:skip_sdkUnZip
%__ECHO% ECHO SET TCLSH_CMD=%TEMP%\%TCLKIT_EXE%%OVERWRITE%"%ROOT%\SetTclKitEnv.bat"
IF DEFINED TCLKIT_NOSDK GOTO skip_sdkVariables
%__ECHO% ECHO SET TCLINCDIR=%TEMP%\%TCLKIT_SDK%\include%APPEND%"%ROOT%\SetTclKitEnv.bat"
%__ECHO% ECHO SET TCLLIBDIR=%TEMP%\%TCLKIT_SDK%\lib%APPEND%"%ROOT%\SetTclKitEnv.bat"
%__ECHO% ECHO SET LIBTCL=%TCLKIT_LIB%%APPEND%"%ROOT%\SetTclKitEnv.bat"
:skip_sdkVariables
GOTO no_errors
:fn_TclKitX86Variables
IF NOT DEFINED TCLKIT_PATCHLEVEL (
SET TCLKIT_PATCHLEVEL=8.6.4
)
SET TCLKIT_EXE=tclkit-%TCLKIT_PATCHLEVEL%.exe
SET TCLKIT_LIB=libtclkit%TCLKIT_PATCHLEVEL:.=%.lib
SET TCLKIT_SDK=libtclkit-sdk-x86-%TCLKIT_PATCHLEVEL%
SET TCLKIT_SDK_ZIP=%TCLKIT_SDK%.zip
SET TCLKIT_FILES=%TCLKIT_EXE% unzip.exe %TCLKIT_SDK_ZIP%
GOTO :EOF
:fn_TclKitX64Variables
IF NOT DEFINED TCLKIT_PATCHLEVEL (
REM
REM NOTE: By default, use latest available version of the TclKit SDK
REM for x64. However, the "default" TclKit executable for x86
REM is still used here because it is the only one "well-known"
REM to be available for download.
REM
SET TCLKIT_PATCHLEVEL=8.6.3
SET TCLKIT_EXE=tclkit-8.6.4.exe
) ELSE (
SET TCLKIT_EXE=tclkit-%TCLKIT_PATCHLEVEL%.exe
)
SET TCLKIT_LIB=libtclkit%TCLKIT_PATCHLEVEL:.=%.lib
SET TCLKIT_SDK=libtclkit-sdk-x64-%TCLKIT_PATCHLEVEL%
SET TCLKIT_SDK_ZIP=%TCLKIT_SDK%.zip
SET TCLKIT_FILES=%TCLKIT_EXE% unzip.exe %TCLKIT_SDK_ZIP%
GOTO :EOF
:fn_UnquoteVariable
IF NOT DEFINED %1 GOTO :EOF
SETLOCAL
SET __ECHO_CMD=ECHO %%%1%%
FOR /F "delims=" %%V IN ('%__ECHO_CMD%') DO (
SET VALUE=%%V
)
SET VALUE=%VALUE:"=%
REM "
ENDLOCAL && SET %1=%VALUE%
GOTO :EOF
:fn_ResetErrorLevel
VERIFY > NUL
GOTO :EOF
:fn_SetErrorLevel
VERIFY MAYBE 2> NUL
GOTO :EOF
:usage
ECHO.
ECHO Usage: %~nx0 ^<processor^>
ECHO.
ECHO The only supported values for processor are "x86" and "x64".
GOTO errors
:errors
CALL :fn_SetErrorLevel
ENDLOCAL
ECHO.
ECHO Failure, errors were encountered.
GOTO end_of_file
:no_errors
CALL :fn_ResetErrorLevel
ENDLOCAL
ECHO.
ECHO Success, no errors were encountered.
GOTO end_of_file
:end_of_file
%__ECHO% EXIT /B %ERRORLEVEL%