From 2c6cd95b39b9681fa8dc4ba331a4ded1f448da65 Mon Sep 17 00:00:00 2001 From: Justin Schuh Date: Tue, 27 Jul 2021 01:40:42 -0700 Subject: [PATCH] build_win.bat: add RUN switch and other changes (#6706) * build_win.bat: add RUN switch and other changes * Adds optional RUN action after a successful build * Adds some more error checking and status messages * Fixes a bug where cmake wasn't run on dirty builds * Fixes a bug in canonicalizing paths with spaces * build_win.bat: Make cached destdir per-config --- build_win.bat | 355 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 281 insertions(+), 74 deletions(-) diff --git a/build_win.bat b/build_win.bat index dac590811..600d6d6e6 100644 --- a/build_win.bat +++ b/build_win.bat @@ -2,67 +2,79 @@ @IF "%PS_ECHO_ON%" NEQ "" (echo on) ELSE (echo off) @GOTO :MAIN :HELP +@ECHO. @ECHO Performs initial build or rebuild of the app (build) and deps (build/deps). @ECHO Default options are determined from build directories and system state. @ECHO. @ECHO Usage: build_win [-ARCH ^] [-CONFIG ^] [-DESTDIR ^] @ECHO [-STEPS ^] +@ECHO [-RUN ^] @ECHO. -@ECHO -a -ARCH Target processor architecture -@ECHO Default: %PS_ARCH_HOST% -@ECHO -c -CONFIG MSVC project config -@ECHO Default: %PS_CONFIG_DEFAULT% -@ECHO -s -STEPS Performs only the specified build steps: -@ECHO all - clean and build deps and app -@ECHO all-dirty - build deps and app without cleaning -@ECHO app - build main project/application -@ECHO app-dirty - does not build main project/application -@ECHO deps - clean and build deps -@ECHO deps-dirty - build deps without cleaning -@ECHO Default: %PS_STEPS_DEFAULT% -@ECHO -d -DESTDIR Deps destination directory (ignored on dirty builds) -@ECHO %PS_DESTDIR_DEFAULT_MSG% +@ECHO -a -ARCH Target processor architecture +@ECHO Default: %PS_ARCH_HOST% +@ECHO -c -CONFIG MSVC project config +@ECHO Default: %PS_CONFIG_DEFAULT% +@ECHO -s -STEPS Performs only the specified build steps: +@ECHO all - clean and build deps and app +@ECHO all-dirty - build deps and app without cleaning +@ECHO app - clean and build main applications +@ECHO app-dirty - build main applications without cleaning +@ECHO deps - clean and build deps +@ECHO deps-dirty - build deps without cleaning +@ECHO Default: %PS_STEPS_DEFAULT% +@ECHO -r -RUN Specifies what to perform at the run step: +@ECHO console - run and wait on prusa-slicer-console.exe +@ECHO custom - run and wait on your custom build/%PS_CUSTOM_RUN_FILE% +@ECHO ide - open project in Visual Studio if not open (no wait) +@ECHO none - run step does nothing +@ECHO viewer - run prusa-gcodeviewer.exe (no wait) +@ECHO window - run prusa-slicer.exe (no wait) +@ECHO Default: none +@ECHO -d -DESTDIR Deps destination directory +@ECHO Warning: Changing destdir path will not delete the old destdir. +@ECHO Default: %PS_DESTDIR_DEFAULT_MSG% @ECHO. -@ECHO Example usage: -@ECHO First build: build_win -d "c:\src\PrusaSlicer-deps" -@ECHO Deps change: build_win -s all -@ECHO App rebuild: build_win +@ECHO Examples: +@ECHO. +@ECHO Initial build: build_win -d "c:\src\PrusaSlicer-deps" +@ECHO Build post deps change: build_win -s all +@ECHO App dirty build: build_win +@ECHO App dirty build ^& run: build_win -r console +@ECHO All clean build ^& run: build_win -s all -r console -d "deps\build\out_deps" @ECHO. GOTO :END :MAIN +REM Script constants SET START_TIME=%TIME% SET PS_START_DIR=%CD% +SET PS_SOLUTION_NAME=PrusaSlicer +SET PS_CHOICE_TIMEOUT=30 +SET PS_CUSTOM_RUN_FILE=custom_run.bat +SET PS_DEPS_PATH_FILE_NAME=.DEPS_PATH.txt +SET PS_DEPS_PATH_FILE=%~dp0deps\build\%PS_DEPS_PATH_FILE_NAME% +SET PS_CONFIG_LIST="Debug;MinSizeRel;Release;RelWithDebInfo" + +REM Probe build directories and system state for reasonable default arguments pushd %~dp0 -REM Probe build directories and sytem state for reasonable default arguments SET PS_CONFIG=RelWithDebInfo -SET PS_ARCH=%PROCESSOR_ARCHITECTURE% +SET PS_ARCH=%PROCESSOR_ARCHITECTURE:amd64=x64% CALL :TOLOWER PS_ARCH -SET PS_DEPS_PATH_FILE=%~dp0deps\build\.DEPS_PATH.txt +SET PS_RUN=none SET PS_DESTDIR= -IF EXIST %PS_DEPS_PATH_FILE% ( - FOR /F "tokens=* USEBACKQ" %%I IN ("%PS_DEPS_PATH_FILE%") DO SET PS_DESTDIR=%%I - IF EXIST build/ALL_BUILD.vcxproj ( - SET PS_STEPS=app-dirty - ) ELSE SET PS_STEPS=app -) ELSE SET PS_STEPS=all -SET PS_DESTDIR_CACHED=%PS_DESTDIR% +CALL :RESOLVE_DESTDIR_CACHE REM Set up parameters used by help menu SET PS_CONFIG_DEFAULT=%PS_CONFIG% SET PS_ARCH_HOST=%PS_ARCH% -SET PS_STEPS_DEFAULT=%PS_STEPS% -IF "%PS_DESTDIR%" NEQ "" ( - SET PS_DESTDIR_DEFAULT_MSG=Default: %PS_DESTDIR% -) ELSE ( - SET PS_DESTDIR_DEFAULT_MSG=Argument required ^(no default available^) -) +(echo " -help /help -h /h -? /? ")| findstr /I /C:" %~1 ">nul && GOTO :HELP REM Parse arguments SET EXIT_STATUS=1 +SET PS_CURRENT_STEP=arguments SET PARSER_STATE= SET PARSER_FAIL= -FOR %%I in (%*) DO CALL :PARSE_OPTION "ARCH CONFIG DESTDIR STEPS" PARSER_STATE "%%~I" +FOR %%I in (%*) DO CALL :PARSE_OPTION "ARCH CONFIG DESTDIR STEPS RUN" PARSER_STATE "%%~I" IF "%PARSER_FAIL%" NEQ "" ( @ECHO ERROR: Invalid switch: %PARSER_FAIL% 1>&2 GOTO :HELP @@ -72,46 +84,71 @@ IF "%PARSER_FAIL%" NEQ "" ( ) REM Validate arguments -SET PS_STEPS_SAVED=%PS_STEPS% -CALL :PARSE_OPTION_NAME "all all-dirty deps-dirty deps app-dirty app" PS_STEPS -%PS_STEPS% -IF "%PS_STEPS%" EQU "" ( - @ECHO ERROR: Invalid parameter: steps=%PS_STEPS_SAVED% 1>&2 - GOTO :HELP -) ELSE SET PS_STEPS_SAVED= -(echo %PS_STEPS%)| findstr /I /C:"dirty">nul && SET PS_STEPS_DIRTY=1 -CALL :TOLOWER PS_STEPS +SET PS_ASK_TO_CONTINUE= CALL :TOLOWER PS_ARCH -CALL :CANONICALIZE_PATH PS_DESTDIR "%PS_START_DIR%" +SET PS_ARCH=%PS_ARCH:amd64=x64% +CALL :PARSE_OPTION_VALUE %PS_CONFIG_LIST:;= % PS_CONFIG +IF "%PS_CONFIG%" EQU "" GOTO :HELP +REM RESOLVE_DESTDIR_CACHE must go after PS_ARCH and PS_CONFIG, but before PS STEPS +CALL :RESOLVE_DESTDIR_CACHE +IF "%PS_STEPS%" EQU "" SET PS_STEPS=%PS_STEPS_DEFAULT% +CALL :PARSE_OPTION_VALUE "all all-dirty deps-dirty deps app-dirty app app-cmake" PS_STEPS +IF "%PS_STEPS%" EQU "" GOTO :HELP +(echo %PS_STEPS%)| findstr /I /C:"dirty">nul && SET PS_STEPS_DIRTY=1 || SET PS_STEPS_DIRTY= +IF "%PS_STEPS%" EQU "app-cmake" SET PS_STEPS_DIRTY=1 +IF "%PS_DESTDIR%" EQU "" SET PS_DESTDIR=%PS_DESTDIR_CACHED% IF "%PS_DESTDIR%" EQU "" ( - IF "%PS_STEPS_DIRTY%" EQU "" ( - @ECHO ERROR: Parameter required: destdir 1>&2 - GOTO :HELP - ) -) ELSE IF "%PS_DESTDIR%" NEQ "%PS_DESTDIR_CACHED%" ( - IF "%PS_STEPS_DIRTY%" NEQ "" ( - @ECHO WARNING: Parameter ignored: destdir - ) ELSE (echo "all deps")| findstr /I /C:"%PS_STEPS%">nul || ( - @ECHO WARNING: Conflict with cached parameter: 1>&2 - @ECHO WARNING: -destdir=%PS_DESTDIR% 1>&2 - @ECHO WARNING: cached=%PS_DESTDIR_CACHED% 1>&2 + @ECHO ERROR: Parameter required: -DESTDIR 1>&2 + GOTO :HELP +) +CALL :CANONICALIZE_PATH PS_DESTDIR "%PS_START_DIR%" +IF "%PS_DESTDIR%" NEQ "%PS_DESTDIR_CACHED%" ( + (echo "all deps all-dirty deps-dirty")| findstr /I /C:"%PS_STEPS%">nul || ( + IF EXIST "%PS_DESTDIR%" ( + @ECHO WARNING: DESTDIR does not match cache: 1>&2 + @ECHO WARNING: new: %PS_DESTDIR% 1>&2 + @ECHO WARNING: old: %PS_DESTDIR_CACHED% 1>&2 + SET PS_ASK_TO_CONTINUE=1 + ) ELSE ( + @ECHO ERROR: Invalid parameter: DESTDIR=%PS_DESTDIR% 1>&2 + GOTO :HELP + ) ) ) SET PS_DESTDIR_DEFAULT_MSG= +CALL :PARSE_OPTION_VALUE "console custom ide none viewer window" PS_RUN +IF "%PS_RUN%" EQU "" GOTO :HELP +IF "%PS_RUN%" NEQ "none" IF "%PS_STEPS:~0,4%" EQU "deps" ( + @ECHO ERROR: RUN=%PS_RUN% specified with STEPS=%PS_STEPS% + @ECHO ERROR: RUN=none is the only valid option for STEPS "deps" or "deps-dirty" + GOTO :HELP +) +REM Give the user a chance to cancel if we found something odd. +IF "%PS_ASK_TO_CONTINUE%" EQU "" GOTO :BUILD_ENV +@ECHO. +@ECHO Unexpected parameters detected. Build paused for %PS_CHOICE_TIMEOUT% seconds. +choice /T %PS_CHOICE_TIMEOUT% /C YN /D N /M "Continue" +IF %ERRORLEVEL% NEQ 1 GOTO :HELP REM Set up MSVC environment +:BUILD_ENV SET EXIT_STATUS=2 +SET PS_CURRENT_STEP=environment @ECHO ********************************************************************** @ECHO ** Build Config: %PS_CONFIG% @ECHO ** Target Arch: %PS_ARCH% @ECHO ** Build Steps: %PS_STEPS% +@ECHO ** Run App: %PS_RUN% @ECHO ** Deps path: %PS_DESTDIR% @ECHO ** Using Microsoft Visual Studio installation found at: -SET VSWHERE="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -IF NOT EXIST %VSWHERE% SET VSWHERE="%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe" -FOR /F "tokens=* USEBACKQ" %%I IN (`%VSWHERE% -nologo -property installationPath`) DO SET MSVC_DIR=%%I +SET VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe +IF NOT EXIST "%VSWHERE%" SET VSWHERE=%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe +FOR /F "tokens=* USEBACKQ" %%I IN (`"%VSWHERE%" -nologo -property installationPath`) DO SET MSVC_DIR=%%I @ECHO ** %MSVC_DIR% CALL "%MSVC_DIR%\Common7\Tools\vsdevcmd.bat" -arch=%PS_ARCH% -host_arch=%PS_ARCH_HOST% -app_platform=Desktop -IF "%ERRORLEVEL%" NEQ "0" GOTO :END +IF %ERRORLEVEL% NEQ 0 GOTO :END +REM Need to reset the echo state after vsdevcmd.bat clobbers it. +@IF "%PS_ECHO_ON%" NEQ "" (echo on) ELSE (echo off) IF "%PS_DRY_RUN_ONLY%" NEQ "" ( @ECHO Script terminated early because PS_DRY_RUN_ONLY is set. 1>&2 GOTO :END @@ -121,36 +158,132 @@ IF /I "%PS_STEPS:~0,3%" EQU "app" GOTO :BUILD_APP REM Build deps :BUILD_DEPS SET EXIT_STATUS=3 -IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY deps\build +SET PS_CURRENT_STEP=deps +IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY deps\build "%PS_DEPS_PATH_FILE_NAME%" cd deps\build || GOTO :END -IF "%PS_STEPS_DIRTY%" EQU "" cmake.exe .. -DDESTDIR="%PS_DESTDIR%" || GOTO :END +cmake.exe .. -DDESTDIR="%PS_DESTDIR%" || GOTO :END (echo %PS_DESTDIR%)> "%PS_DEPS_PATH_FILE%" msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% || GOTO :END cd ..\.. -IF /I "%PS_STEPS:~0,4%" EQU "deps" GOTO :PROLOGUE +IF /I "%PS_STEPS:~0,4%" EQU "deps" GOTO :RUN_APP REM Build app :BUILD_APP SET EXIT_STATUS=4 -IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY build +SET PS_CURRENT_STEP=app +IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY build "%PS_CUSTOM_RUN_FILE%" cd build || GOTO :END -IF "%PS_STEPS_DIRTY%" EQU "" cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" || GOTO :END -msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% || GOTO :END +REM Make sure we have a custom batch file skeleton for the run stage +set PS_CUSTOM_BAT=%PS_CUSTOM_RUN_FILE% +CALL :CANONICALIZE_PATH PS_CUSTOM_BAT +IF NOT EXIST %PS_CUSTOM_BAT% CALL :WRITE_CUSTOM_SCRIPT_SKELETON %PS_CUSTOM_BAT% +SET PS_PROJECT_IS_OPEN= +FOR /F "tokens=2 delims=," %%I in ( + 'tasklist /V /FI "IMAGENAME eq devenv.exe " /NH /FO CSV ^| find "%PS_SOLUTION_NAME%"' +) do SET PS_PROJECT_IS_OPEN=%%~I +cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG_LIST% || GOTO :END +REM Skip the build step if we're using the undocumented app-cmake to regenerate the full config from inside devenv +IF "%PS_STEPS%" NEQ "app-cmake" msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% || GOTO :END +(echo %PS_DESTDIR%)> "%PS_DEPS_PATH_FILE_FOR_CONFIG%" + +REM Run app +:RUN_APP +REM All build steps complete. +CALL :DIFF_TIME ELAPSED_TIME %START_TIME% %TIME% +IF "%PS_CURRENT_STEP%" NEQ "arguments" ( + @ECHO. + @ECHO Total Build Time Elapsed %ELAPSED_TIME% +) +SET EXIT_STATUS=5 +SET PS_CURRENT_STEP=run +cd src\%PS_CONFIG% || GOTO :END +IF "%PS_RUN%" EQU "none" GOTO :PROLOGUE +SET PS_PROJECT_IS_OPEN= +FOR /F "tokens=2 delims=," %%I in ( + 'tasklist /V /FI "IMAGENAME eq devenv.exe " /NH /FO CSV ^| find "%PS_SOLUTION_NAME%"' +) do SET PS_PROJECT_IS_OPEN=%%~I +@ECHO. +@ECHO Running %PS_RUN% application... +@REM icacls below is just a hack for file-not-found error handling +IF "%PS_RUN%" EQU "console" ( + icacls prusa-slicer-console.exe >nul || GOTO :END + start /wait /b prusa-slicer-console.exe +) ELSE IF "%PS_RUN%" EQU "window" ( + icacls prusa-slicer.exe >nul || GOTO :END + start prusa-slicer.exe +) ELSE IF "%PS_RUN%" EQU "viewer" ( + icacls prusa-gcodeviewer.exe >nul || GOTO :END + start prusa-gcodeviewer.exe +) ELSE IF "%PS_RUN%" EQU "custom" ( + icacls %PS_CUSTOM_BAT% >nul || GOTO :END + CALL %PS_CUSTOM_BAT% +) ELSE IF "%PS_RUN%" EQU "ide" ( + IF "%PS_PROJECT_IS_OPEN%" NEQ "" ( + @ECHO WARNING: Solution is already open in Visual Studio. Skipping ide run step. 1>&2 + ) ELSE ( + @ECHO Preparing to run Visual Studio... + cd ..\.. || GOTO :END + REM This hack generates a single config for MSVS, guaranteeing it gets set as the active config. + cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG% > nul 2> nul || GOTO :END + REM Now launch devenv with the single config (setting it active) and a /command switch to re-run cmake and generate the full config list + start devenv.exe %PS_SOLUTION_NAME%.sln /command ^"shell /o ^^^"%~f0^^^" -d ^^^"%PS_DESTDIR%^^^" -c %PS_CONFIG% -a %PS_ARCH% -r none -s app-cmake^" + REM If devenv fails to launch just directly regenerate the full config list. + IF %ERRORLEVEL% NEQ 0 ( + cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG_LIST% 2> nul 1> nul || GOTO :END + ) + ) +) + +@REM ********** DON'T ADD ANY CODE BETWEEN THESE TWO SECTIONS ********** +@REM RUN_APP may hand off control, so let exit codes fall through to PROLOGUE. :PROLOGUE SET EXIT_STATUS=%ERRORLEVEL% :END @IF "%PS_ECHO_ON%%PS_DRY_RUN_ONLY%" NEQ "" ( - @ECHO Script Parameters: + @ECHO ********************************************************************** + @ECHO ** Script Parameters: + @ECHO ********************************************************************** @SET PS_ ) -@ECHO Script started at %START_TIME% and completed at %TIME%. +IF "%EXIT_STATUS%" NEQ "0" ( + IF "%PS_CURRENT_STEP%" NEQ "arguments" ( + @ECHO. + @ECHO ERROR: *** Build process failed at %PS_CURRENT_STEP% step. *** 1>&2 + ) +) ELSE ( + @ECHO All steps completed successfully. +) popd exit /B %EXIT_STATUS% GOTO :EOF REM Functions and stubs start here. +:RESOLVE_DESTDIR_CACHE +@REM Resolves all DESTDIR cache values and sets PS_STEPS_DEFAULT +@REM Note: This just sets global variableq, so it doesn't use setlocal. +SET PS_DEPS_PATH_FILE_FOR_CONFIG=%~dp0build\%PS_ARCH%\%PS_CONFIG%\%PS_DEPS_PATH_FILE_NAME% +CALL :CANONICALIZE_PATH PS_DEPS_PATH_FILE_FOR_CONFIG +IF EXIST "%PS_DEPS_PATH_FILE_FOR_CONFIG%" ( + FOR /F "tokens=* USEBACKQ" %%I IN ("%PS_DEPS_PATH_FILE_FOR_CONFIG%") DO ( + SET PS_DESTDIR_CACHED=%%I + SET PS_DESTDIR_DEFAULT_MSG=%%I + ) + SET PS_STEPS_DEFAULT=app-dirty +) ELSE IF EXIST "%PS_DEPS_PATH_FILE%" ( + FOR /F "tokens=* USEBACKQ" %%I IN ("%PS_DEPS_PATH_FILE%") DO ( + SET PS_DESTDIR_CACHED=%%I + SET PS_DESTDIR_DEFAULT_MSG=%%I + ) + SET PS_STEPS_DEFAULT=app +) ELSE ( + SET PS_DESTDIR_CACHED= + SET PS_DESTDIR_DEFAULT_MSG=Cache missing. Argument required. + SET PS_STEPS_DEFAULT=all +) +GOTO :EOF + :PARSE_OPTION @REM Argument parser called for each argument @REM %1 - Valid option list @@ -179,12 +312,27 @@ IF "%LAST_ARG%%ARG_TYPE%" EQU "NAME" SET PARSER_FAIL=%~3 ) GOTO :EOF +:PARSE_OPTION_VALUE +setlocal disableDelayedExpansion +@REM Parses value and verifies it is within the supplied list +@REM %1 - Valid option list +@REM %2 - In/out variable name; unset on error +CALL SET NAME=%~2 +CALL SET SAVED_VALUE=%%%NAME%%% +CALL :PARSE_OPTION_NAME %1 %NAME% -%SAVED_VALUE% +CALL SET NEW_VALUE=%%%NAME%%% +IF "%NEW_VALUE%" EQU "" ( + @ECHO ERROR: Invalid parameter: %NAME:~3%=%SAVED_VALUE% 1>&2 +) +endlocal & SET %NAME%=%NEW_VALUE% +GOTO :EOF + :PARSE_OPTION_NAME @REM Parses an option name @REM %1 - Valid option list @REM %2 - Out variable name; unset on error @REM %3 - Current argument value -@REM $4 - Boolean indicating single character switches are valid +@REM %4 - Boolean indicating single character switches are valid @REM Note: Delayed expansion safe because ! character is invalid in option name setlocal enableDelayedExpansion IF "%4" NEQ "" FOR %%I IN (%~1) DO @( @@ -201,6 +349,7 @@ IF "%4" NEQ "" ( ) @(echo %OPTION_NAME%)| findstr /R /C:".[ ][ ]*.">nul && GOTO :PARSE_OPTION_NAME_FAIL @(echo %~1 )| findstr /I /C:" %OPTION_NAME% ">nul || GOTO :PARSE_OPTION_NAME_FAIL +FOR %%I IN (%~1) DO SET OPTION_NAME=!OPTION_NAME:%%~I=%%~I! endlocal & SET %~2=%OPTION_NAME% GOTO :EOF :PARSE_OPTION_NAME_FAIL @@ -210,14 +359,28 @@ GOTO :EOF :MAKE_OR_CLEAN_DIRECTORY @REM Create directory if it doesn't exist or clean it if it does @REM %1 - Directory path to clean or create +@REM %* - Optional list of files/dirs to keep (in the base directory only) setlocal disableDelayedExpansion IF NOT EXIST "%~1" ( - ECHO Creating %~1 - mkdir "%~1" && GOTO :EOF + @ECHO Creating %~1 + mkdir "%~1" && ( + endlocal + GOTO :EOF + ) +) +@ECHO Cleaning %~1 ... +SET KEEP_LIST= +:MAKE_OR_CLEAN_DIRECTORY_ARG_LOOP +IF "%~2" NEQ "" ( + SET KEEP_LIST=%KEEP_LIST% "%~2" + SHIFT /2 + GOTO :MAKE_OR_CLEAN_DIRECTORY_ARG_LOOP ) -ECHO Cleaning %~1 ... for /F "usebackq delims=" %%I in (`dir /a /b "%~1"`) do ( - (rmdir /s /q "%~1\%%I" 2>nul ) || del /q /f "%~1\%%I") + (echo %KEEP_LIST%)| findstr /I /L /C:"\"%%I\"">nul || ( + rmdir /s /q "%~1\%%I" 2>nul ) || del /q /f "%~1\%%I" +) +endlocal GOTO :EOF :TOLOWER @@ -239,7 +402,51 @@ CALL :CANONICALIZE_PATH_INNER %1 %%%~1%% %2 endlocal & SET %~1=%OUTPUT% GOTO :EOF :CANONICALIZE_PATH_INNER -if "%~3" NEQ "" (pushd %~3 || GOTO :EOF) +if "%~3" NEQ "" (pushd %3 || GOTO :EOF) SET OUTPUT=%~f2 -if "%~3" NEQ "" popd %~3 +if "%~3" NEQ "" popd +GOTO :EOF + +:DIFF_TIME +@REM Calculates elapsed time between two timestamps (TIME environment variable format) +@REM %1 - Output variable +@REM %2 - Start time +@REM %3 - End time +setlocal EnableDelayedExpansion +set START_ARG=%2 +set END_ARG=%3 +set END=!END_ARG:%TIME:~8,1%=%%100)*100+1! +set START=!START_ARG:%TIME:~8,1%=%%100)*100+1! +set /A DIFF=((((10!END:%TIME:~2,1%=%%100)*60+1!%%100)-((((10!START:%TIME:~2,1%=%%100)*60+1!%%100), DIFF-=(DIFF^>^>31)*24*60*60*100 +set /A CC=DIFF%%100+100,DIFF/=100,SS=DIFF%%60+100,DIFF/=60,MM=DIFF%%60+100,HH=DIFF/60+100 +@endlocal & set %1=%HH:~1%%TIME:~2,1%%MM:~1%%TIME:~2,1%%SS:~1%%TIME:~8,1%%CC:~1% +@GOTO :EOF + +:WRITE_CUSTOM_SCRIPT_SKELETON +@REM Writes the following text to the supplied file +@REM %1 - Output filename +setlocal +@( +ECHO @ECHO. +ECHO @ECHO ******************************************************************************** +ECHO @ECHO ** This is a custom run script skeleton. +ECHO @ECHO ******************************************************************************** +ECHO @ECHO. +ECHO @ECHO ******************************************************************************** +ECHO @ECHO ** The working directory is: +ECHO @ECHO ******************************************************************************** +ECHO dir +ECHO @ECHO. +ECHO @ECHO ******************************************************************************** +ECHO @ECHO ** The environment is: +ECHO @ECHO ******************************************************************************** +ECHO set +ECHO @ECHO. +ECHO @ECHO ******************************************************************************** +ECHO @ECHO ** Edit or replace this script to run custom steps after a successful build: +ECHO @ECHO ** %~1 +ECHO @ECHO ******************************************************************************** +ECHO @ECHO. +) > "%~1" +endlocal GOTO :EOF