99 "encoding/xml"
1010 "errors"
1111 "fmt"
12+ "hash/fnv"
1213 "io"
1314 "net/http"
1415 neturl "net/url"
@@ -38,6 +39,8 @@ const (
3839 nugetBuildMaxTimeout = 6 * time .Hour
3940 nugetCommandIdleTimeout = 30 * time .Second
4041 nugetPreflightTimeout = 8 * time .Second
42+ nugetRestoreBinlogDir = ".murphysec"
43+ nugetTmpBinlogDir = "murphysec-nuget-binlogs"
4144)
4245
4346type nugetConfigXML struct {
@@ -453,8 +456,77 @@ func startCommandIdleWatchdog(
453456 }
454457}
455458
459+ func nugetRestoreBinlogName (solutionPath string ) string {
460+ base := filepath .Base (solutionPath )
461+ ext := filepath .Ext (base )
462+ name := strings .TrimSuffix (base , ext )
463+ if name == "" {
464+ name = "restore"
465+ }
466+ return name + ".restore.binlog"
467+ }
468+
469+ func nugetRestoreBinlogPath (solutionPath string ) string {
470+ return filepath .Join (filepath .Dir (solutionPath ), nugetRestoreBinlogDir , nugetRestoreBinlogName (solutionPath ))
471+ }
472+
473+ func nugetRestoreTmpBinlogPath (solutionPath string ) string {
474+ hasher := fnv .New32a ()
475+ _ , _ = hasher .Write ([]byte (filepath .Clean (solutionPath )))
476+ return filepath .Join (
477+ os .TempDir (),
478+ nugetTmpBinlogDir ,
479+ fmt .Sprintf ("%08x" , hasher .Sum32 ()),
480+ nugetRestoreBinlogName (solutionPath ),
481+ )
482+ }
483+
484+ func copyFile (srcPath , dstPath string ) error {
485+ src , err := os .Open (srcPath )
486+ if err != nil {
487+ return err
488+ }
489+ defer src .Close ()
490+
491+ if err = os .MkdirAll (filepath .Dir (dstPath ), 0o755 ); err != nil {
492+ return err
493+ }
494+ dst , err := os .Create (dstPath )
495+ if err != nil {
496+ return err
497+ }
498+ defer dst .Close ()
499+
500+ if _ , err = io .Copy (dst , src ); err != nil {
501+ return err
502+ }
503+ return dst .Close ()
504+ }
505+
506+ func archiveNugetRestoreBinlog (logger * zap.Logger , solutionPath string ) (string , error ) {
507+ srcPath := nugetRestoreBinlogPath (solutionPath )
508+ if _ , err := os .Stat (srcPath ); err != nil {
509+ return "" , err
510+ }
511+ dstPath := nugetRestoreTmpBinlogPath (solutionPath )
512+ if err := copyFile (srcPath , dstPath ); err != nil {
513+ return "" , err
514+ }
515+ if logger != nil {
516+ logger .Sugar ().Infof ("NuGet restore binary log copied to tmp: %s" , dstPath )
517+ }
518+ return dstPath , nil
519+ }
520+
456521func dotnetRestoreArgs (solutionPath string ) []string {
457- args := []string {"restore" , solutionPath , "-v" , "detailed" }
522+ binlogPath := nugetRestoreBinlogPath (solutionPath )
523+ args := []string {
524+ "restore" ,
525+ solutionPath ,
526+ "-v" ,
527+ "detailed" ,
528+ fmt .Sprintf ("/bl:%s;ProjectImports=Embed" , binlogPath ),
529+ }
458530 if runtime .GOOS == "linux" {
459531 args = append (args , "-p:EnableWindowsTargeting=true" )
460532 }
@@ -468,7 +540,14 @@ func dotnetListPackageArgs(solutionPath string) []string {
468540// 通过先运行 dotnet restore 命令,确保项目中的所有 NuGet 包依赖项被正确恢复
469541func buildPackage (ctx context.Context , logger * zap.Logger , solutionPath string ) (err error ) {
470542 //dotnet restore
543+ binlogPath := nugetRestoreBinlogPath (solutionPath )
544+ if err = os .MkdirAll (filepath .Dir (binlogPath ), 0o755 ); err != nil {
545+ err = fmt .Errorf ("create nuget binlog dir failed: %w" , err )
546+ logger .Error (err .Error ())
547+ return
548+ }
471549 args := dotnetRestoreArgs (solutionPath )
550+ logger .Sugar ().Infof ("NuGet restore binary log enabled: %s" , binlogPath )
472551 if runtime .GOOS == "linux" {
473552 logger .Info ("dotnet restore adds EnableWindowsTargeting for Linux compatibility" )
474553 }
@@ -556,6 +635,11 @@ func buildPackage(ctx context.Context, logger *zap.Logger, solutionPath string)
556635 wg .Wait ()
557636 close (done )
558637 err = cmd .Wait ()
638+ if archivePath , archiveErr := archiveNugetRestoreBinlog (logger , solutionPath ); archiveErr != nil {
639+ logger .Sugar ().Warnf ("copy NuGet restore binary log to tmp failed: src=%s err=%v" , binlogPath , archiveErr )
640+ } else {
641+ logger .Sugar ().Infof ("NuGet restore binary log archive ready: %s" , archivePath )
642+ }
559643 if err != nil {
560644 if idleTimeoutExceeded .Load () {
561645 return fmt .Errorf ("dotnet restore idle timed out after %s without new output: %w\n stderr:\n %s\n stdout:\n %s" ,
0 commit comments