@REM  -----------------------------------------------------------------
@REM
@REM  drivercab.cmd - BPerkins
@REM     generates driver.cab for each sku
@REM
@REM  Copyright (c) Microsoft Corporation. All rights reserved.
@REM
@REM  -----------------------------------------------------------------
@if defined _CPCMAGIC goto CPCBegin
@perl -x "%~f0" %*
@goto :EOF
#!perl
use strict;
use lib $ENV{RAZZLETOOLPATH} . "\\PostBuildScripts";
use lib $ENV{RAZZLETOOLPATH};
use PbuildEnv;
use ParseArgs;

sub Usage { print<<USAGE; exit(1) }
drivercab [-l <language>]

Generates driver.cab for each sku using *drivers.txt files generated by 
cddata from drvindex.inf.
USAGE

parseargs('?' => \&Usage);


#             *** TEMPLATE CODE ***
$ENV{"_CPCMAGIC"}++;exit(system($0)>>8);
__END__
@:CPCBegin
@set _CPCMAGIC=
@setlocal ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS
@if not defined DEBUG echo off
@REM          *** CMD SCRIPT BELOW ***

REM
REM drivercab.cmd
REM

REM this script will generate a driver.cab for each sku appropriate to this
REM language. the files to be used are contained in drvindex.inf for each
REM sku, which is read by cddata.cmd, and passed through txt files here.

REM details:
REM we are passed .txt lists for each sku, and then a file called
REM commondrivers.txt for all common files. if the commondrivers.txt file
REM exists, we can assume that we are not in incremental mode, as the idea
REM of a common cab doesn't really make sense in an incremental environment.
REM
REM if commondrivers.txt does not exist, we will use cabinc.exe to add
REM the changed files in each SKU to the appropriate driver.cab
REM
REM if perdrivers.txt does not exist, then there are no changes for per or
REM alternately the per cab is equivalent to the common cab if not in
REM incremental mode.


REM
REM setup
REM
REM get all appropriate products
call logmsg.cmd "Calculating which products to act on ..."
set Products=
for %%a in (pro per bla sbs srv ads dtc) do (
   perl %RazzleToolPath%\cksku.pm -t:%%a -l:%lang% -a:%_BuildArch%
   if !ErrorLevel! == 0 (
      if not defined Products (
         set Products=%%a
      ) else (
         set Products=!Products! %%a
      )
   )
)
call logmsg.cmd "Checking for incremental mode ..."
set IncMode=TRUE
if exist %TMP%\commondrivers.txt set IncMode=


REM set up the temp cab locations
set TmpCabLocation=%_NTPOSTBLD%\cabs\driver\cabs
if not exist %TmpCabLocation% md %TmpCabLocation%

REM
REM test for incremental mode
REM
if defined IncMode goto :PerformIncrementalCabbing
goto :PerformFullCabbing





REM
REM PerformIncrementalCabbing
REM
REM here we just want to go through our product list, and use cabinc.exe
REM to replace the old entries in driver.cab with the new ones.
REM
:PerformIncrementalCabbing
call logmsg.cmd "Performing incremental cabbing ..."


REM loop over products and cabinc the files in
for %%a in (%Products%) do (
   REM the call to :SetMyInfDirName just sets the MyInfDirName env var to
   REM whatever the inf subdir for that product is, like for ads it is entinf
   set MyInfDirName=
   call :SetMyInfDirName %%a
   if not defined MyInfDirName (
      call errmsg.cmd "Invalid sku %%a found ..."
   )
   set MyDriverCab=%_NTPOSTBLD%\!MyInfDirName!\driver.cab
   if not exist !MyDriverCab! (
      call errmsg.cmd "Can't perform incremental updates without full cabs ..."
      goto :End
   )
   set MyFileList=%TMP%\%%adrivers.txt
   if not exist !MyFileList! (
      call logmsg.cmd "No files to change for %%a sku ..."
   ) else (
      call logmsg.cmd "Replacing files for %%a sku ..."
      set IncCommand=
      set NewFiles=
      for /f %%b in (!MyFileList!) do (
         set NewFile=%_NTPOSTBLD%\%%b
         for %%c in (!NewFile!) do set NewFileName=%%~nxc
         extract.exe -d !MyDriverCab! !NewFileName! | findstr /ic:"No matching files"
         if !ErrorLevel! NEQ 0 (
            REM this file was already in the cab, replace it
            set IncCommand=!IncCommand! !NewFile!
         ) else (
            REM this file is new to the cab, add it
            set NewFiles=!NewFiles! mergefile !NewFile!
         )
      )
      if defined IncCommand (
         call ExecuteCmd.cmd "cabinc.exe -t %NUMBER_OF_PROCESSORS% -q 40 -p 80 !MyDriverCab! !IncCommand!"
         if !ErrorLevel! NEQ 0 (
            call errmsg.cmd "Replace failed for %%a sku, file was !NewFile!,"
            call errmsg.cmd "cab file was !MyDriverCab! ..."
         ) else (
            call logmsg.cmd "!NewFileName! replaced in !MyDriverCab! ..."
         )
      )
      if defined NewFiles (
         call ExecuteCmd.cmd "cabbench.exe load !MyDriverCab! !NewFiles! save !MyDriverCab!.new"
         if !ErrorLevel! NEQ 0 (
            call errmsg.cmd "Add failed for %%a sku, file was !NewFile!,"
            call errmsg.cmd "cab file was !MyDriverCab! ..."
         ) else (
            call ExecuteCmd.cmd "del !MyDriverCab!"
            call ExecuteCmd.cmd "ren !MyDriverCab!.new driver.cab"
            call logmsg.cmd "!NewFileName! added to !MyDriverCab! ..."
         )
      )
   )
)
call logmsg.cmd "Finished."

goto :End


REM
REM PerformFullCabbing
REM
REM here we want to break the common list into NUM_PROCS sublists, then
REM multithread generation of those sub cabs. after that, we mash them all
REM back together, and then multithread generation of the sku specific cabs.
REM finally, we mash the sku specific cabs onto the common cab for each sku,
REM and put those in the fooinf\driver.cab position.
REM
:PerformFullCabbing
call logmsg.cmd "Performing full cabbing ..."


REM
REM first, do the common cab. we want to break the list down into NUM_PROCS
REM lists, so we can thread them nicely
REM
call logmsg.cmd "Finding common drivers list ..."
set CommonList=%TMP%\commondrivers.txt
if not exist %CommonList% (
   call errmsg.cmd "Could not find %CommonList% to generate driver.cab ..."
   goto :End
)
set BackupName=%TMP%\backuplist.txt
if exist %BackupName% del /f /q %BackupName%
move %CommonList% %BackupName%
if exist %CommonList%.* del /f /q %CommonList%.*
move %BackupName% %CommonList%
set /a NumLists=%NUMBER_OF_PROCESSORS%
call logmsg.cmd "Splitting common drivers list into %NumLists% parts ..."
perl %RazzleToolPath%\PostBuildScripts\splitlist.pl -n %NumLists% -f %CommonList% -l %lang%
REM splitlist.pl creates commondrivers.txt.1, commondrivers.txt.2, etc
set /a NumThreads=0
for /l %%a in (1,1,%NumLists%) do (
   if exist %CommonList%.%%a set /a NumThreads=%%a
)
REM now NumThreads is the list count
call logmsg.cmd "Created %NumThreads% sub lists ..."
REM set the common cab name and location
set CommonCab=%TmpCabLocation%\common.cab
if exist %CommonCab% del /f %CommonCab%
if exist %CommonCab% (
   call errmsg.cmd "Failed to delete old common cab ..."
   goto :End
)


REM
REM now, we want to kick off our child processes and wait for them to finish.
REM the wrapper script will generate the DDF from the list we pass it on the
REM command line, in this case something like %TMP%\commondrivers.txt.1
REM

set EventList=
for /l %%a in (1,1,%NumThreads%) do (
   call logmsg.cmd "Starting %CommonCab%.%%a cab ..."
   set EventName=commoncab%%a
   start "PB_CommonCab.%%a" /min cmd /c CabWrapper.cmd %CommonList%.%%a %CommonCab%.%%a !EventName!"
   set EventList=!EventList! !EventName!
)
if not defined EventList (
   REM hmmm?
   call errmsg.cmd "No events to wait on for common cabs ..."
) else (
   call logmsg.cmd "Waiting for common cabs ..."
   perl %RazzleToolPath%\PostBuildScripts\cmdevt.pl -iwv !EventList!
)


REM
REM check if there were errors in the generation
REM
call logmsg.cmd "Checking for errors in sub cab generation ..."
findstr /ic:"ERROR:" %LOGFILE% >nul 2>nul
if %ErrorLevel% == 0 (
   REM we found some errors
   call errmsg.cmd "There were errors generating the sub cabs for driver.cab"
   call errmsg.cmd "Please investigate or run postbuild -full"
   goto :End
)


REM
REM the common cab now needs to be merged together. we will use cabbench.exe
REM to do this
REM
call logmsg.cmd "Merging common cab pieces back together ..."
if %NumThreads% == 1 (
   REM only one cab, just rename it
   call logmsg.cmd "Only one common cab, renaming ..."
   move %TmpCabLocation%\common.cab.1 %CommonCab%
) else (
   REM multiple cabs, merge them
   set MergeCommand=load %TmpCabLocation%\common.cab.1
   for /l %%a in (2,1,%NumThreads%) do (
      set MergeCommand=!MergeCommand! load %TmpCabLocation%\common.cab.%%a merge
   )
   set MergeCommand=!MergeCommand! save %CommonCab%
   call logmsg.cmd "Issuing merge ..."
   call ExecuteCmd.cmd "cabbench.exe !MergeCommand!"
   if !ErrorLevel! NEQ 0 (
      call errmsg.cmd "Merge of common cab failed ..."
      goto :End
   )
)
if not exist %CommonCab% (
   call errmsg.cmd "Common cab does not exist at %CommonCab% after merge ..."
   goto :End
)
call logmsg.cmd "Merge successful, continuing ..."


REM
REM now, we get to create the sub cabs for each sku. just kick off as many
REM threads as we need to do this, and give the short lists to the wrapper.
REM the wrapper will handle creating the DDFs from the lists we pass it.
REM
call logmsg.cmd "Creating sku specific cabs ..."
set EventList=
for %%a in (%Products%) do (
   if not exist %TMP%\%%adrivers.txt (
      call logmsg.cmd "No drivers to cab for %%a sku ..."
   ) else (
      rem 4chan: add timeout between cabwrapper calls, should help with collisions under newer OSs
      sleep 3
      call logmsg.cmd "Starting generation for %%a specific drivers ..."
      set EventName=%%adrivercab
      REM syntax for CabWrapper.cmd is:
      REM    list of files
      REM    cab name to create
      REM    event name to signal
      start "PB_%%adrivercab" /min cmd /c CabWrapper.cmd %TMP%\%%adrivers.txt %TmpCabLocation%\%%adriver.cab !EventName!
      set EventList=!EventList! !EventName!
   )
)
if not defined EventList (
   REM no events to wait for? okay ... whatever ...
   call logmsg.cmd "No sku specific cabs to wait for, continuing ..."
) else (
   call logmsg.cmd "Waiting for sku specific cabs to generate ..."
   perl %RazzleToolPath%\PostBuildScripts\cmdevt.pl -iwv %EventList%
)


REM
REM now we have the common cab and the sku specific cabs, let's merge them
REM into full sku particular driver.cab files
REM
for %%a in (%Products%) do (
   set MySkuCab=%_NTPOSTBLD%\%%ainf\driver.cab
   if /i "%%a" == "pro" set MySkuCab=%_NTPOSTBLD%\driver.cab
   if /i "%%a" == "ads" set MySkuCab=%_NTPOSTBLD%\entinf\driver.cab
   if not exist %TmpCabLocation%\%%adriver.cab (
      call logmsg.cmd "No %%a specific cab, copying common cab in place ..."
      copy %CommonCab% !MySkuCab!
   ) else (
      call logmsg.cmd "Merging %%a specific and common cabs ..."
      set MergeCommand=load %TmpCabLocation%\%%adriver.cab
      set MergeCommand=!MergeCommand! load %CommonCab%
      set MergeCommand=!MergeCommand! merge save !MySkuCab!
      call ExecuteCmd.cmd "cabbench.exe !MergeCommand!"
      if !ErrorLevel! NEQ 0 (
         call errmsg.cmd "Merge of %%a driver.cab failed ..."
      ) else (
         call logmsg.cmd "Merge of %%a driver.cab successful ..."
      )
   )
)


REM
REM and we're done
REM
call logmsg.cmd "Finished."


goto :End



:SetMyInfDirName
set SkuName=%1
set MyInfDirName=
if /i "%SkuName%" == "pro" set MyInfDirName=.
if /i "%SkuName%" == "per" set MyInfDirName=perinf
if /i "%SkuName%" == "bla" set MyInfDirName=blainf
if /i "%SkuName%" == "sbs" set MyInfDirName=sbsinf
if /i "%SkuName%" == "srv" set MyInfDirName=srvinf
if /i "%SkuName%" == "ads" set MyInfDirName=entinf
if /i "%SkuName%" == "dtc" set MyInfDirName=dtcinf
goto :End



:end
if "%errors%" == "" set errors=0
seterror.exe "%errors%"& goto :EOF