Skip to content

Commit 36755a4

Browse files
committed
Update config.guess for all R packages
Factor out the check and obtain config.guess from ConfigureMake into free functions to be able to use them inside the rpackage EB. Change the workflow for R packages to always extract which is more in line with the regular workflow for other EasyConfigs. This then allows to search for config.guess files to replace by the downloaded version contained within EasyBuild.
1 parent 85c2f77 commit 36755a4

File tree

2 files changed

+114
-93
lines changed

2 files changed

+114
-93
lines changed

easybuild/easyblocks/generic/configuremake.py

Lines changed: 95 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,99 @@
6666
DEFAULT_BUILD_CMD = 'make'
6767
DEFAULT_INSTALL_CMD = 'make install'
6868

69+
def check_config_guess(config_guess, log=None):
70+
"""Check timestamp & SHA256 checksum of config.guess script.
71+
72+
:param configu_gess: Path to config.guess script to check
73+
:param log: Instance of a logger to use or None to run in quiet mode
74+
:return: Whether the script is valid (matches the version and checksum)
75+
"""
76+
# config.guess includes a "timestamp='...'" indicating the version
77+
config_guess_version = None
78+
version_regex = re.compile("^timestamp='(.*)'", re.M)
79+
res = version_regex.search(read_file(config_guess))
80+
if res:
81+
config_guess_version = res.group(1)
82+
83+
config_guess_checksum = compute_checksum(config_guess, checksum_type=CHECKSUM_TYPE_SHA256)
84+
try:
85+
config_guess_timestamp = datetime.fromtimestamp(os.stat(config_guess).st_mtime).isoformat()
86+
except OSError as err:
87+
if log:
88+
log.warning("Failed to determine timestamp of %s: %s", config_guess, err)
89+
config_guess_timestamp = None
90+
91+
# log version, timestamp & SHA256 checksum of config.guess
92+
if log:
93+
log.info("config.guess version: %s (last updated: %s, SHA256 checksum: %s)",
94+
config_guess_version, config_guess_timestamp, config_guess_checksum)
95+
96+
result = True
97+
98+
if config_guess_version != CONFIG_GUESS_VERSION:
99+
result = False
100+
tup = (config_guess, config_guess_version, CONFIG_GUESS_VERSION)
101+
if log:
102+
log.warning("config.guess version at %s does not match expected version: %s vs %s" % tup)
103+
if config_guess_checksum != CONFIG_GUESS_SHA256:
104+
result = False
105+
tup = (config_guess, config_guess_checksum, CONFIG_GUESS_SHA256)
106+
if log:
107+
log.warning("SHA256 checksum of config.guess at %s does not match expected checksum: %s vs %s" % tup)
108+
109+
return result
110+
111+
def obtain_config_guess(download_source_path=None, search_source_paths=None, log=None):
112+
"""
113+
Locate or download an up-to-date config.guess
114+
115+
:param download_source_path: Path to download config.guess to
116+
:param search_source_paths: Paths to search for config.guess
117+
:param log: Instance of a logger to use or None to run in quiet mode
118+
:return: Path to config.guess or None
119+
"""
120+
eb_source_paths = source_paths()
121+
if download_source_path is None:
122+
download_source_path = eb_source_paths[0]
123+
if search_source_paths is None:
124+
search_source_paths = eb_source_paths
125+
126+
config_guess = 'config.guess'
127+
sourcepath_subdir = os.path.join('generic', 'eb_v%s' % EASYBLOCKS_VERSION, 'ConfigureMake')
128+
129+
config_guess_path = None
130+
131+
# check if config.guess has already been downloaded to source path
132+
for path in eb_source_paths:
133+
cand_config_guess_path = os.path.join(path, sourcepath_subdir, config_guess)
134+
if os.path.isfile(cand_config_guess_path):
135+
config_guess_path = cand_config_guess_path
136+
if log:
137+
log.info("Found recent %s at %s, using it if required", config_guess, config_guess_path)
138+
break
139+
140+
# if not found, try to download it
141+
if config_guess_path is None:
142+
cand_config_guess_path = os.path.join(download_source_path, sourcepath_subdir, config_guess)
143+
config_guess_url = CONFIG_GUESS_URL_STUB + CONFIG_GUESS_COMMIT_ID
144+
downloaded_path = download_file(config_guess, config_guess_url, cand_config_guess_path)
145+
if downloaded_path is not None:
146+
# verify SHA256 checksum of download to avoid using a corrupted download
147+
if verify_checksum(downloaded_path, CONFIG_GUESS_SHA256):
148+
config_guess_path = downloaded_path
149+
# add execute permissions
150+
adjust_permissions(downloaded_path, stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH, add=True)
151+
if log:
152+
log.info("Downloaded recent %s to %s, using it if required", config_guess, config_guess_path)
153+
else:
154+
if log:
155+
log.warning("Checksum failed for downloaded file %s, not using it!", downloaded_path)
156+
remove_file(downloaded_path)
157+
elif log:
158+
log.warning("Failed to download recent %s to %s", config_guess, cand_config_guess_path)
159+
160+
return config_guess_path
161+
69162

70163
class ConfigureMake(EasyBlock):
71164
"""
@@ -106,74 +199,13 @@ def obtain_config_guess(self, download_source_path=None, search_source_paths=Non
106199
:param search_source_paths: Paths to search for config.guess
107200
:return: Path to config.guess or None
108201
"""
109-
eb_source_paths = source_paths()
110-
if download_source_path is None:
111-
download_source_path = eb_source_paths[0]
112-
if search_source_paths is None:
113-
search_source_paths = eb_source_paths
114-
115-
config_guess = 'config.guess'
116-
sourcepath_subdir = os.path.join('generic', 'eb_v%s' % EASYBLOCKS_VERSION, 'ConfigureMake')
117-
118-
config_guess_path = None
119-
120-
# check if config.guess has already been downloaded to source path
121-
for path in eb_source_paths:
122-
cand_config_guess_path = os.path.join(path, sourcepath_subdir, config_guess)
123-
if os.path.isfile(cand_config_guess_path):
124-
config_guess_path = cand_config_guess_path
125-
self.log.info("Found recent %s at %s, using it if required", config_guess, config_guess_path)
126-
break
127-
128-
# if not found, try to download it
129-
if config_guess_path is None:
130-
cand_config_guess_path = os.path.join(download_source_path, sourcepath_subdir, config_guess)
131-
config_guess_url = CONFIG_GUESS_URL_STUB + CONFIG_GUESS_COMMIT_ID
132-
downloaded_path = download_file(config_guess, config_guess_url, cand_config_guess_path)
133-
if downloaded_path is not None:
134-
# verify SHA256 checksum of download to avoid using a corrupted download
135-
if verify_checksum(downloaded_path, CONFIG_GUESS_SHA256):
136-
config_guess_path = downloaded_path
137-
# add execute permissions
138-
adjust_permissions(downloaded_path, stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH, add=True)
139-
self.log.info("Downloaded recent %s to %s, using it if required", config_guess, config_guess_path)
140-
else:
141-
self.log.warning("Checksum failed for downloaded file %s, not using it!", downloaded_path)
142-
remove_file(downloaded_path)
143-
else:
144-
self.log.warning("Failed to download recent %s to %s for use with ConfigureMake easyblock (if needed)",
145-
config_guess, cand_config_guess_path)
146-
147-
return config_guess_path
202+
return obtain_config_guess(download_source_path, search_source_paths, log=self.log)
148203

149204
def check_config_guess(self):
150205
"""Check timestamp & SHA256 checksum of config.guess script."""
151206
# log version, timestamp & SHA256 checksum of config.guess that was found (if any)
152207
if self.config_guess:
153-
# config.guess includes a "timestamp='...'" indicating the version
154-
config_guess_version = None
155-
version_regex = re.compile("^timestamp='(.*)'", re.M)
156-
res = version_regex.search(read_file(self.config_guess))
157-
if res:
158-
config_guess_version = res.group(1)
159-
160-
config_guess_checksum = compute_checksum(self.config_guess, checksum_type=CHECKSUM_TYPE_SHA256)
161-
try:
162-
config_guess_timestamp = datetime.fromtimestamp(os.stat(self.config_guess).st_mtime).isoformat()
163-
except OSError as err:
164-
self.log.warning("Failed to determine timestamp of %s: %s", self.config_guess, err)
165-
config_guess_timestamp = None
166-
167-
self.log.info("config.guess version: %s (last updated: %s, SHA256 checksum: %s)",
168-
config_guess_version, config_guess_timestamp, config_guess_checksum)
169-
170-
if config_guess_version != CONFIG_GUESS_VERSION:
171-
tup = (self.config_guess, config_guess_version, CONFIG_GUESS_VERSION)
172-
print_warning("config.guess version at %s does not match expected version: %s vs %s" % tup)
173-
174-
if config_guess_checksum != CONFIG_GUESS_SHA256:
175-
tup = (self.config_guess, config_guess_checksum, CONFIG_GUESS_SHA256)
176-
print_warning("SHA256 checksum of config.guess at %s does not match expected checksum: %s vs %s" % tup)
208+
check_config_guess(self.config_guess, log=self.log)
177209

178210
def fetch_step(self, *args, **kwargs):
179211
"""Custom fetch step for ConfigureMake so we use an updated config.guess."""

easybuild/easyblocks/generic/rpackage.py

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,11 @@
3636
import shutil
3737

3838
from easybuild.easyblocks.r import EXTS_FILTER_R_PACKAGES, EB_R
39+
from easybuild.easyblocks.generic.configuremake import check_config_guess, obtain_config_guess
3940
from easybuild.framework.easyconfig import CUSTOM
4041
from easybuild.framework.extensioneasyblock import ExtensionEasyBlock
4142
from easybuild.tools.build_log import EasyBuildError
42-
from easybuild.tools.filetools import mkdir
43+
from easybuild.tools.filetools import mkdir, copy_file
4344
from easybuild.tools.run import run_cmd, parse_log_for_error
4445

4546

@@ -132,12 +133,8 @@ def make_cmdline_cmd(self, prefix=None):
132133
else:
133134
prefix = ''
134135

135-
if self.cfg['unpack_sources']:
136-
loc = self.start_dir
137-
elif self.patches:
138-
loc = self.ext_dir
139-
else:
140-
loc = self.ext_src
136+
loc = self.start_dir or self.ext_dir or self.ext_src
137+
141138
cmd = ' '.join([
142139
self.cfg['preinstallopts'],
143140
"R CMD INSTALL",
@@ -152,23 +149,6 @@ def make_cmdline_cmd(self, prefix=None):
152149
self.log.debug("make_cmdline_cmd returns %s" % cmd)
153150
return cmd, None
154151

155-
def extract_step(self):
156-
"""Source should not be extracted."""
157-
158-
if self.cfg['unpack_sources']:
159-
super(RPackage, self).extract_step()
160-
elif len(self.src) > 1:
161-
raise EasyBuildError("Don't know how to handle R packages with multiple sources.'")
162-
else:
163-
try:
164-
shutil.copy2(self.src[0]['path'], self.builddir)
165-
except OSError as err:
166-
raise EasyBuildError("Failed to copy source to build dir: %s", err)
167-
self.ext_src = self.src[0]['name']
168-
169-
# set final path since it can't be determined from unpacked sources (used for guessing start_dir)
170-
self.src[0]['finalpath'] = self.builddir
171-
172152
def configure_step(self):
173153
"""No configuration for installing R packages."""
174154
pass
@@ -195,9 +175,19 @@ def install_R_package(self, cmd, inp=None):
195175
else:
196176
self.log.debug("R package %s installed succesfully" % self.name)
197177

178+
def update_config_guess(self, src_dir):
179+
"""Update any config.guess found in src_dir"""
180+
for config_guess_dir in (root for root, _, files in os.walk(src_dir) if 'config.guess' in files):
181+
config_guess = os.path.join(config_guess_dir, 'config.guess')
182+
if not check_config_guess(config_guess):
183+
updated_config_guess = obtain_config_guess(log=self.log)
184+
copy_file(updated_config_guess, config_guess)
185+
198186
def install_step(self):
199187
"""Install procedure for R packages."""
200-
188+
# Update config.guess if the package was extracted
189+
if self.start_dir:
190+
self.update_config_guess(self.start_dir)
201191
cmd, stdin = self.make_cmdline_cmd(prefix=os.path.join(self.installdir, self.cfg['exts_subdir']))
202192
self.install_R_package(cmd, inp=stdin)
203193

@@ -215,16 +205,15 @@ def run(self):
215205
lib_install_prefix = os.path.join(self.installdir, self.cfg['exts_subdir'])
216206
mkdir(lib_install_prefix, parents=True)
217207

218-
if self.patches:
219-
super(RPackage, self).run(unpack_src=True)
220-
else:
221-
super(RPackage, self).run()
222-
223208
if self.src:
209+
super(RPackage, self).run(unpack_src=True)
224210
self.ext_src = self.src
211+
self.update_config_guess(self.ext_dir)
225212
self.log.debug("Installing R package %s version %s." % (self.name, self.version))
226213
cmd, stdin = self.make_cmdline_cmd(prefix=lib_install_prefix)
227214
else:
215+
if self.patches:
216+
raise EasyBuildError("Cannot patch R package %s as no explicit source is given!", self.name)
228217
self.log.debug("Installing most recent version of R package %s (source not found)." % self.name)
229218
cmd, stdin = self.make_r_cmd(prefix=lib_install_prefix)
230219

0 commit comments

Comments
 (0)