Skip to content

Commit

Permalink
Merge pull request #2042 from Darkless012/add_gopackage_easyblock
Browse files Browse the repository at this point in the history
Add GoPackage EasyBlock
  • Loading branch information
boegel authored Apr 27, 2020
2 parents 4d3ea06 + e728aae commit 566a14f
Show file tree
Hide file tree
Showing 2 changed files with 154 additions and 0 deletions.
148 changes: 148 additions & 0 deletions easybuild/easyblocks/generic/gopackage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
##
# Copyright 2009-2020 Ghent University
#
# This file is part of EasyBuild,
# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),
# with support of Ghent University (http://ugent.be/hpc),
# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),
# Flemish Research Foundation (FWO) (http://www.fwo.be/en)
# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).
#
# https://github.com/easybuilders/easybuild
#
# EasyBuild is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation v2.
#
# EasyBuild is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with EasyBuild. If not, see <http://www.gnu.org/licenses/>.
##
"""
EasyBuild support for Go packages, implemented as an EasyBlock
@author: Pavel Grochal (INUITS)
"""
import os
from distutils.version import LooseVersion

import easybuild.tools.environment as env
from easybuild.framework.easyblock import EasyBlock
from easybuild.framework.easyconfig import CUSTOM
from easybuild.tools.build_log import EasyBuildError
from easybuild.tools.modules import get_software_root, get_software_version
from easybuild.tools.run import run_cmd


class GoPackage(EasyBlock):
"""Builds and installs a Go package, and provides a dedicated module file."""

@staticmethod
def extra_options(extra_vars=None):
"""Easyconfig parameters specific to Go packages."""
if extra_vars is None:
extra_vars = {}
extra_vars.update({
'modulename': [None, "Module name of the Go package, when building non-native module", CUSTOM],
'forced_deps': [None, "Force specific version of Go package, when building non-native module", CUSTOM],
})
return extra_vars

def prepare_step(self, *args, **kwargs):
"""Go-specific preparations."""
super(GoPackage, self).prepare_step(*args, **kwargs)

if get_software_root('Go') is None:
raise EasyBuildError("Failed to pick go command to use. Is it listed in dependencies?")

if LooseVersion(get_software_version('Go')) < LooseVersion("1.11"):
raise EasyBuildError("Go version < 1.11 doesn't support installing modules from go.mod")

def configure_step(self):
"""Configure Go package build/install."""

# enforce use of go modules
env.setvar('GO111MODULE', 'on', verbose=False)
# set bin folder
env.setvar('GOBIN', os.path.join(self.installdir, 'bin'), verbose=False)

# creates log entries for go being used, for debugging
run_cmd("go version", verbose=False, trace=False)
run_cmd("go env", verbose=False, trace=False)

def build_step(self):
"""If Go package is not native go module, lets try to make the module."""

go_mod_file = 'go.mod'
go_sum_file = 'go.sum'

if not os.path.exists(go_mod_file) or not os.path.isfile(go_mod_file):
self.log.warn("go.mod not found! This is not natively supported go module. Trying to init module.")

if self.cfg['modulename'] is None:
raise EasyBuildError("Installing non-native go module. You need to specify 'modulename' in easyconfig")

# for more information about migrating to go modules
# see: https://blog.golang.org/migrating-to-go-modules

# go mod init
cmd = ' '.join(['go', 'mod', 'init', self.cfg['modulename']])
run_cmd(cmd, log_all=True, simple=True)

if self.cfg['forced_deps']:
for dep in self.cfg['forced_deps']:
# go get specific dependencies which locks them in go.mod
cmd = ' '.join(['go', 'get', '%s@%s' % dep])
run_cmd(cmd, log_all=True, simple=True)

# note: ... (tripledot) used below is not a typo, but go wildcard pattern
# which means: anything you can find in this directory, including all subdirectories
# see: 'go help packages' or https://golang.org/pkg/cmd/go/internal/help/
# see: https://stackoverflow.com/a/28031651/2047157

# building and testing will add packages to go.mod
run_cmd('go build ./...', log_all=True, simple=True)
run_cmd('go test ./...', log_all=True, simple=True)

# tidy up go.mod
run_cmd('go mod tidy', log_all=True, simple=True)

# build and test again, to ensure go mod tidy didn't removed anything needed
run_cmd('go build ./...', log_all=True, simple=True)
run_cmd('go test ./...', log_all=True, simple=True)

self.log.warn('Include generated go.mod and go.sum via patch to ensure locked dependencies '
'and run this easyconfig again.')
run_cmd('cat go.mod', log_all=True, simple=True)
run_cmd('cat go.sum', log_all=True, simple=True)

if not os.path.exists(go_sum_file) or not os.path.isfile(go_sum_file):
raise EasyBuildError("go.sum not found! This module has no locked dependency versions.")

def install_step(self):
"""Install Go package to a custom path"""

# actually install Go package
cmd = ' '.join([
self.cfg['preinstallopts'],
'go',
'install',
self.cfg['installopts'],
])
run_cmd(cmd, log_all=True, log_ok=True, simple=True)

def sanity_check_step(self):
"""Custom sanity check for Go package."""

# Check if GoPackage produced binary and can run help on it
custom_paths = {
'files': ['bin/%s' % self.name.lower()],
'dirs': [],
}
custom_commands = ['%s --help' % self.name.lower()]

super(GoPackage, self).sanity_check_step(custom_paths=custom_paths, custom_commands=custom_commands)
6 changes: 6 additions & 0 deletions test/easyblocks/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import easybuild.tools.toolchain.utilities as tc_utils
from easybuild.base import fancylogger
from easybuild.base.testing import TestCase
from easybuild.easyblocks.generic.gopackage import GoPackage
from easybuild.easyblocks.generic.intelbase import IntelBase
from easybuild.easyblocks.generic.pythonbundle import PythonBundle
from easybuild.easyblocks.imod import EB_IMOD
Expand Down Expand Up @@ -234,6 +235,11 @@ def template_module_only_test(self, easyblock, name='foo', version='1.3.2', extr
# $EBROOTPYTHON must be set for PythonBundle easyblock
os.environ['EBROOTPYTHON'] = '/fake/install/prefix/Python/2.7.14-foss-2018a'

elif app_class == GoPackage:
# $EBROOTGO must be set for GoPackage easyblock
os.environ['EBROOTGO'] = '/fake/install/prefix/Go/1.14'
os.environ['EBVERSIONGO'] = '1.14'

elif app_class == EB_OpenFOAM:
# proper toolchain must be used for OpenFOAM(-Extend), to determine value to set for $WM_COMPILER
write_file(os.path.join(tmpdir, 'GCC', '4.9.3-2.25'), '\n'.join([
Expand Down

0 comments on commit 566a14f

Please sign in to comment.