@@ -22,7 +22,7 @@ import (
2222 "gopkg.in/yaml.v3"
2323)
2424
25- const agentVersion = "1.1 .0"
25+ const agentVersion = "1.2 .0"
2626
2727type RemoteIndex struct {
2828 GeneratedAt int64 `json:"generatedAt"`
@@ -429,6 +429,7 @@ func cmdCheckZipType(args []string) {
429429
430430 hasManifest := false
431431 hasServerFiles := false
432+ hasFTBInstaller := false
432433
433434 startScripts := []string {"run.sh" , "install.sh" , "start.sh" , "run.bat" , "install.bat" , "start.bat" }
434435 dirsToCheck := []string {"mods/" , "config/" , "libraries/" , "serverpack/" }
@@ -437,6 +438,9 @@ func cmdCheckZipType(args []string) {
437438 if f .Name == "manifest.json" {
438439 hasManifest = true
439440 }
441+ if zipFileContainsFTBInstallerReference (f ) {
442+ hasFTBInstaller = true
443+ }
440444
441445 for _ , script := range startScripts {
442446 if f .Name == script {
@@ -457,7 +461,9 @@ func cmdCheckZipType(args []string) {
457461 }
458462 }
459463
460- if hasManifest {
464+ if hasFTBInstaller {
465+ fmt .Println ("ftb-preconfigured" )
466+ } else if hasManifest {
461467 fmt .Println ("manifest" )
462468 } else if hasServerFiles {
463469 fmt .Println ("preconfigured" )
@@ -636,6 +642,14 @@ func processFlattenPack(zipPath string, targetDir string, executeInstallScript b
636642 }
637643 }
638644
645+ ftbBootstrap , err := findFTBInstallerBootstrap (targetDir )
646+ if err != nil {
647+ return err
648+ }
649+ if ftbBootstrap != "" {
650+ return installFTBServerPack (ftbBootstrap , targetDir )
651+ }
652+
639653 startScripts := []string {"run.sh" , "install.sh" , "start.sh" }
640654 var scriptsFound []string
641655 for _ , scriptName := range startScripts {
@@ -665,6 +679,109 @@ func processFlattenPack(zipPath string, targetDir string, executeInstallScript b
665679 return nil
666680}
667681
682+ func zipFileContainsFTBInstallerReference (file * zip.File ) bool {
683+ name := strings .ToLower (filepath .Base (filepath .ToSlash (file .Name )))
684+ if name != "install.sh" && name != "install.bat" {
685+ return false
686+ }
687+ rc , err := file .Open ()
688+ if err != nil {
689+ return false
690+ }
691+ defer rc .Close ()
692+ content , err := io .ReadAll (io .LimitReader (rc , 256 * 1024 ))
693+ if err != nil {
694+ return false
695+ }
696+ return containsFTBInstallerReference (string (content ))
697+ }
698+
699+ func containsFTBInstallerReference (content string ) bool {
700+ normalized := strings .ToLower (content )
701+ return strings .Contains (normalized , "ftbteam/ftb-server-installer" ) || strings .Contains (normalized , "ftb-server-installer_" ) || strings .Contains (normalized , "ftb-server-" )
702+ }
703+
704+ func findFTBInstallerBootstrap (targetDir string ) (string , error ) {
705+ bootstrap := ""
706+ err := filepath .WalkDir (targetDir , func (path string , entry os.DirEntry , err error ) error {
707+ if err != nil {
708+ return err
709+ }
710+ if entry .IsDir () {
711+ relative , relativeErr := filepath .Rel (targetDir , path )
712+ if relativeErr == nil && relative != "." && strings .Count (filepath .ToSlash (relative ), "/" ) >= 2 {
713+ return filepath .SkipDir
714+ }
715+ return nil
716+ }
717+ if ! strings .EqualFold (entry .Name (), "install.sh" ) {
718+ return nil
719+ }
720+ content , readErr := os .ReadFile (path )
721+ if readErr != nil {
722+ return readErr
723+ }
724+ if containsFTBInstallerReference (string (content )) {
725+ bootstrap = path
726+ return io .EOF
727+ }
728+ return nil
729+ })
730+ if err != nil && err != io .EOF {
731+ return "" , err
732+ }
733+ return bootstrap , nil
734+ }
735+
736+ func installFTBServerPack (bootstrapPath string , targetDir string ) error {
737+ bootstrapDir := filepath .Dir (bootstrapPath )
738+ bootstrap := exec .Command ("/bin/sh" , "./" + filepath .Base (bootstrapPath ))
739+ bootstrap .Dir = bootstrapDir
740+ if output , err := bootstrap .CombinedOutput (); err != nil {
741+ return fmt .Errorf ("FTB installer bootstrap failed: %w\n %s" , err , string (output ))
742+ }
743+
744+ entries , err := os .ReadDir (bootstrapDir )
745+ if err != nil {
746+ return err
747+ }
748+ installerPath := ""
749+ for _ , entry := range entries {
750+ name := strings .ToLower (entry .Name ())
751+ if ! entry .IsDir () && strings .HasPrefix (name , "ftb-server-installer" ) && ! strings .HasSuffix (name , ".log" ) {
752+ installerPath = filepath .Join (bootstrapDir , entry .Name ())
753+ break
754+ }
755+ }
756+ if installerPath == "" {
757+ return fmt .Errorf ("FTB server installer binary was not downloaded" )
758+ }
759+ if err := os .Chmod (installerPath , 0o755 ); err != nil {
760+ return fmt .Errorf ("make FTB server installer executable: %w" , err )
761+ }
762+
763+ installer := exec .Command (installerPath , "-auto" , "-force" , "-no-colours" , "-dir" , targetDir )
764+ installer .Dir = bootstrapDir
765+ installer .Stdout = os .Stdout
766+ installer .Stderr = os .Stderr
767+ if err := installer .Run (); err != nil {
768+ return fmt .Errorf ("FTB server installer failed: %w" , err )
769+ }
770+
771+ startupPath := filepath .Join (targetDir , "run.sh" )
772+ if info , err := os .Stat (startupPath ); err != nil || info .IsDir () {
773+ return fmt .Errorf ("FTB server installer completed without creating run.sh" )
774+ }
775+ manifestPath := filepath .Join (targetDir , ".manifest.json" )
776+ if info , err := os .Stat (manifestPath ); err != nil || info .IsDir () {
777+ return fmt .Errorf ("FTB server installer completed without creating .manifest.json" )
778+ }
779+ if err := os .Chmod (startupPath , 0o755 ); err != nil {
780+ return fmt .Errorf ("make FTB startup script executable: %w" , err )
781+ }
782+ return nil
783+ }
784+
668785func fetchAll (mf FetchManifest ) error {
669786 sem := make (chan struct {}, mf .Concurrency )
670787 var wg sync.WaitGroup
0 commit comments