github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/ci/packages/package.go (about)

     1  /*
     2   * Copyright (C) 2019 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package packages
    19  
    20  import (
    21  	"fmt"
    22  	"os"
    23  	"path"
    24  	"strings"
    25  	"text/template"
    26  
    27  	"github.com/magefile/mage/mg"
    28  	"github.com/magefile/mage/sh"
    29  	"github.com/rs/zerolog/log"
    30  
    31  	"github.com/mysteriumnetwork/go-ci/env"
    32  	"github.com/mysteriumnetwork/go-ci/job"
    33  	"github.com/mysteriumnetwork/go-ci/shell"
    34  	"github.com/mysteriumnetwork/node/ci/deb"
    35  	"github.com/mysteriumnetwork/node/ci/storage"
    36  	"github.com/mysteriumnetwork/node/logconfig"
    37  )
    38  
    39  // PackageLinuxAmd64 builds and stores linux amd64 package
    40  func PackageLinuxAmd64() error {
    41  	logconfig.Bootstrap()
    42  	if err := packageStandalone("build/myst/myst_linux_amd64", "linux", "amd64", nil); err != nil {
    43  		return err
    44  	}
    45  	return env.IfRelease(storage.UploadArtifacts)
    46  }
    47  
    48  // PackageLinuxArm builds and stores linux arm package
    49  func PackageLinuxArm() error {
    50  	logconfig.Bootstrap()
    51  	if err := packageStandalone("build/myst/myst_linux_arm", "linux", "arm", nil); err != nil {
    52  		return err
    53  	}
    54  	return env.IfRelease(storage.UploadArtifacts)
    55  }
    56  
    57  // PackageLinuxArmv6l builds and stores linux armv6 package
    58  func PackageLinuxArmv6l() error {
    59  	logconfig.Bootstrap()
    60  	extraEnv := map[string]string{
    61  		"GOARM": "6",
    62  	}
    63  	if err := packageStandalone("build/myst/myst_linux_armv6l", "linux", "arm", extraEnv); err != nil {
    64  		return err
    65  	}
    66  	return env.IfRelease(storage.UploadArtifacts)
    67  }
    68  
    69  // PackageLinuxDebianAmd64 builds and stores debian amd64 package
    70  func PackageLinuxDebianAmd64() error {
    71  	logconfig.Bootstrap()
    72  	if err := goGet("github.com/debber/debber-v0.3/cmd/debber"); err != nil {
    73  		return err
    74  	}
    75  	envi := map[string]string{
    76  		"GOOS":   "linux",
    77  		"GOARCH": "amd64",
    78  	}
    79  	if err := sh.RunWith(envi, "bin/build"); err != nil {
    80  		return err
    81  	}
    82  	if err := packageDebian("build/myst/myst", "amd64"); err != nil {
    83  		return err
    84  	}
    85  	return env.IfRelease(storage.UploadArtifacts)
    86  }
    87  
    88  // PackageLinuxDebianArm builds and stores debian armv7l+ package
    89  func PackageLinuxDebianArm() error {
    90  	logconfig.Bootstrap()
    91  	if err := goGet("github.com/debber/debber-v0.3/cmd/debber"); err != nil {
    92  		return err
    93  	}
    94  	envi := map[string]string{
    95  		"GOOS":   "linux",
    96  		"GOARCH": "arm",
    97  	}
    98  	if err := sh.RunWith(envi, "bin/build"); err != nil {
    99  		return err
   100  	}
   101  	if err := packageDebian("build/myst/myst", "armhf"); err != nil {
   102  		return err
   103  	}
   104  	return env.IfRelease(storage.UploadArtifacts)
   105  }
   106  
   107  // PackageLinuxDebianArmv6l builds and stores debian armv6l package
   108  func PackageLinuxDebianArmv6l() error {
   109  	logconfig.Bootstrap()
   110  	if err := goGet("github.com/debber/debber-v0.3/cmd/debber"); err != nil {
   111  		return err
   112  	}
   113  	envi := map[string]string{
   114  		"GOOS":   "linux",
   115  		"GOARCH": "arm",
   116  		"GOARM":  "6",
   117  	}
   118  	if err := sh.RunWith(envi, "bin/build"); err != nil {
   119  		return err
   120  	}
   121  	if err := packageDebian("build/myst/myst", "armv6l"); err != nil {
   122  		return err
   123  	}
   124  	return env.IfRelease(storage.UploadArtifacts)
   125  }
   126  
   127  // PackageLinuxDebianArm64 builds and stores debian arm64 package
   128  func PackageLinuxDebianArm64() error {
   129  	logconfig.Bootstrap()
   130  	if err := goGet("github.com/debber/debber-v0.3/cmd/debber"); err != nil {
   131  		return err
   132  	}
   133  	envi := map[string]string{
   134  		"GOOS":   "linux",
   135  		"GOARCH": "arm64",
   136  	}
   137  	if err := sh.RunWith(envi, "bin/build"); err != nil {
   138  		return err
   139  	}
   140  	if err := packageDebian("build/myst/myst", "arm64"); err != nil {
   141  		return err
   142  	}
   143  	return env.IfRelease(storage.UploadArtifacts)
   144  }
   145  
   146  // PackageMacOSAmd64 builds and stores macOS amd64 package
   147  func PackageMacOSAmd64() error {
   148  	logconfig.Bootstrap()
   149  	if err := packageStandalone("build/myst/myst_darwin_amd64", "darwin", "amd64", nil); err != nil {
   150  		return err
   151  	}
   152  	return env.IfRelease(storage.UploadArtifacts)
   153  }
   154  
   155  // PackageMacOSArm64 builds and stores macOS arm64 package
   156  func PackageMacOSArm64() error {
   157  	logconfig.Bootstrap()
   158  	if err := packageStandalone("build/myst/myst_darwin_arm64", "darwin", "arm64", nil); err != nil {
   159  		return err
   160  	}
   161  	return env.IfRelease(storage.UploadArtifacts)
   162  }
   163  
   164  // PackageWindowsAmd64 builds and stores Windows amd64 package
   165  func PackageWindowsAmd64() error {
   166  	logconfig.Bootstrap()
   167  	if err := packageStandalone("build/myst/myst_windows_amd64.exe", "windows", "amd64", nil); err != nil {
   168  		return err
   169  	}
   170  	return env.IfRelease(storage.UploadArtifacts)
   171  }
   172  
   173  // PackageAndroid builds and stores Android package
   174  func PackageAndroid() error {
   175  	job.Precondition(func() bool {
   176  		pr, _ := env.IsPR()
   177  		fullBuild, _ := env.IsFullBuild()
   178  		return !pr || fullBuild
   179  	})
   180  	logconfig.Bootstrap()
   181  
   182  	if err := sh.RunV("bin/package_android", "amd64"); err != nil {
   183  		return err
   184  	}
   185  
   186  	// Artifacts created by xgo (docker) on CI environment are owned by root.
   187  	// Chown package folder so we can create a POM (see below) in it.
   188  	if _, isCI := os.LookupEnv("CI"); isCI {
   189  		err := shell.NewCmd("sudo chown -R gitlab-runner:gitlab-runner build/package").Run()
   190  		if err != nil {
   191  			return err
   192  		}
   193  	}
   194  
   195  	err := env.EnsureEnvVars(env.BuildVersion)
   196  	if err != nil {
   197  		return err
   198  	}
   199  	pomTemplate, err := template.ParseFiles("bin/package/android/mvn.pom")
   200  	if err != nil {
   201  		return err
   202  	}
   203  
   204  	buildVersion := env.Str(env.BuildVersion)
   205  	log.Info().Msgf("Package Android SDK version: %s", buildVersion)
   206  
   207  	pomFileOut, err := os.Create(fmt.Sprintf("build/package/mobile-node-%s.pom", buildVersion))
   208  	if err != nil {
   209  		return err
   210  	}
   211  	defer pomFileOut.Close()
   212  
   213  	err = pomTemplate.Execute(pomFileOut, struct {
   214  		BuildVersion string
   215  	}{
   216  		BuildVersion: buildVersion,
   217  	})
   218  	if err != nil {
   219  		return err
   220  	}
   221  
   222  	return env.IfRelease(storage.UploadArtifacts)
   223  }
   224  
   225  // PackageAndroidProvider builds and stores Android Provider package
   226  func PackageAndroidProvider() error {
   227  	job.Precondition(func() bool {
   228  		pr, _ := env.IsPR()
   229  		fullBuild, _ := env.IsFullBuild()
   230  		return !pr || fullBuild
   231  	})
   232  	logconfig.Bootstrap()
   233  
   234  	if err := sh.RunV("bin/package_android_provider", "amd64"); err != nil {
   235  		return err
   236  	}
   237  
   238  	// Artifacts created by xgo (docker) on CI environment are owned by root.
   239  	// Chown package folder so we can create a POM (see below) in it.
   240  	if _, isCI := os.LookupEnv("CI"); isCI {
   241  		err := shell.NewCmd("sudo chown -R gitlab-runner:gitlab-runner build/package").Run()
   242  		if err != nil {
   243  			return err
   244  		}
   245  	}
   246  
   247  	err := env.EnsureEnvVars(env.BuildVersion)
   248  	if err != nil {
   249  		return err
   250  	}
   251  	pomTemplate, err := template.ParseFiles("bin/package/android_provider/mvn.pom")
   252  	if err != nil {
   253  		return err
   254  	}
   255  
   256  	buildVersion := env.Str(env.BuildVersion)
   257  	log.Info().Msgf("Package Android Provider SDK version: %s", buildVersion)
   258  
   259  	pomFileOut, err := os.Create(fmt.Sprintf("build/package/provider-mobile-node-%s.pom", buildVersion))
   260  	if err != nil {
   261  		return err
   262  	}
   263  	defer pomFileOut.Close()
   264  
   265  	err = pomTemplate.Execute(pomFileOut, struct {
   266  		BuildVersion string
   267  	}{
   268  		BuildVersion: buildVersion,
   269  	})
   270  	if err != nil {
   271  		return err
   272  	}
   273  
   274  	return env.IfRelease(storage.UploadArtifacts)
   275  }
   276  
   277  func binFmtSupport() error {
   278  	return sh.RunV("docker", "run", "--rm", "--privileged", "linuxkit/binfmt:v0.8")
   279  }
   280  
   281  func makeCacheRef(cacheRepo string) string {
   282  	return cacheRepo + ":build-cache"
   283  }
   284  
   285  func buildDockerImage(dockerfile string, buildArgs map[string]string, cacheRepo string, tags []string, push bool, platforms []string) error {
   286  	mg.Deps(binFmtSupport)
   287  
   288  	if platforms == nil {
   289  		platforms = []string{
   290  			"linux/amd64",
   291  			"linux/arm64",
   292  			"linux/arm",
   293  		}
   294  	}
   295  
   296  	args := []string{
   297  		"docker", "buildx", "build",
   298  		"--file", dockerfile,
   299  		"--platform", strings.Join(platforms, ","),
   300  		"--output", fmt.Sprintf("type=image,push=%v", push),
   301  	}
   302  	for buildArgKey, buildArgValue := range buildArgs {
   303  		args = append(args, "--build-arg", buildArgKey+"="+buildArgValue)
   304  	}
   305  	for _, tag := range tags {
   306  		args = append(args, "--tag", tag)
   307  	}
   308  
   309  	if cacheRepo != "" {
   310  		args = append(args, "--cache-to=type=registry,mode=max,ref="+makeCacheRef(cacheRepo))
   311  		args = append(args, "--cache-from=type=registry,ref="+makeCacheRef(cacheRepo))
   312  	}
   313  
   314  	args = append(args, ".")
   315  
   316  	return sh.RunV(args[0], args[1:]...)
   317  }
   318  
   319  // BuildMystAlpineImage wraps buildDockerImage with required
   320  // parameters to build myst on Alpine
   321  func BuildMystAlpineImage(tags []string, push bool) error {
   322  	return buildDockerImage(
   323  		path.Join("bin", "docker", "alpine", "Dockerfile"),
   324  		map[string]string{
   325  			string(env.BuildBranch):  env.Str(env.BuildBranch),
   326  			string(env.BuildCommit):  env.Str(env.BuildCommit),
   327  			string(env.BuildNumber):  env.Str(env.BuildNumber),
   328  			string(env.BuildVersion): env.Str(env.BuildVersion),
   329  		},
   330  		"mysteriumnetwork/myst",
   331  		tags,
   332  		push,
   333  		nil,
   334  	)
   335  }
   336  
   337  // BuildMystDocumentationImage wraps buildDockerImage with required
   338  // parameters to build TequilAPI ReDoc image
   339  func BuildMystDocumentationImage(tags []string, push bool) error {
   340  	return buildDockerImage(
   341  		path.Join("bin", "docs_docker", "Dockerfile"),
   342  		nil,
   343  		"mysteriumnetwork/documentation",
   344  		tags,
   345  		push,
   346  		[]string{
   347  			"linux/amd64",
   348  		},
   349  	)
   350  }
   351  
   352  // PackageDockerAlpine builds and stores docker alpine image
   353  func PackageDockerAlpine() error {
   354  	logconfig.Bootstrap()
   355  	return BuildMystAlpineImage([]string{"myst:alpine"}, false)
   356  }
   357  
   358  // PackageDockerSwaggerRedoc builds and stores docker swagger redoc image
   359  func PackageDockerSwaggerRedoc() error {
   360  	logconfig.Bootstrap()
   361  
   362  	err := BuildMystDocumentationImage([]string{"tequilapi"}, false)
   363  	if err != nil {
   364  		return err
   365  	}
   366  
   367  	return env.IfRelease(func() error {
   368  		return storage.UploadSingleArtifact("tequilapi/docs/swagger.json")
   369  	})
   370  }
   371  
   372  func goGet(pkg string) error {
   373  	return sh.RunWith(map[string]string{"GO111MODULE": "off"}, "go", "get", "-u", pkg)
   374  }
   375  
   376  func packageStandalone(binaryPath, os, arch string, extraEnvs map[string]string) error {
   377  	log.Info().Msgf("Packaging %s %s %s", binaryPath, os, arch)
   378  	var err error
   379  	if os == "linux" {
   380  		filename := path.Base(binaryPath)
   381  		binaryPath = path.Join("build", filename, filename)
   382  		err = buildBinaryFor(path.Join("cmd", "mysterium_node", "mysterium_node.go"), filename, os, arch, extraEnvs, true)
   383  	} else {
   384  		err = buildCrossBinary(os, arch)
   385  	}
   386  	if err != nil {
   387  		return err
   388  	}
   389  
   390  	err = buildBinaryFor(path.Join("cmd", "supervisor", "supervisor.go"), "myst_supervisor", os, arch, extraEnvs, true)
   391  	if err != nil {
   392  		return err
   393  	}
   394  
   395  	envs := map[string]string{
   396  		"BINARY": binaryPath,
   397  	}
   398  	return sh.RunWith(envs, "bin/package_standalone", os)
   399  }
   400  
   401  func packageDebian(binaryPath, arch string) error {
   402  	if err := env.EnsureEnvVars(env.BuildVersion); err != nil {
   403  		return err
   404  	}
   405  	envs := map[string]string{
   406  		"BINARY": binaryPath,
   407  	}
   408  
   409  	if err := deb.TermsTemplateFile("bin/package/installation/templates"); err != nil {
   410  		return err
   411  	}
   412  
   413  	return sh.RunWith(envs, "bin/package_debian", env.Str(env.BuildVersion), arch)
   414  }