Source code for law.contrib.cms.tasks
# coding: utf-8
"""
CMS-related tasks.
https://home.cern/about/experiments/cms
"""
from __future__ import annotations
__all__ = ["BundleCMSSW"]
import os
import subprocess
import pathlib
import abc
import luigi # type: ignore[import-untyped]
from law.task.base import Task
from law.target.file import get_path, FileSystemFileTarget
from law.target.local import LocalFileTarget
from law.parameter import NO_STR, CSVParameter
from law.decorator import log
from law.util import rel_path, interruptable_popen, quote_cmd
[docs]
class BundleCMSSW(Task):
task_namespace = "law.cms"
exclude = luigi.Parameter(
default=NO_STR,
significant=False,
description="regular expression for excluding files or directories relative to CMSSW_BASE; "
"default: empty",
)
include = CSVParameter(
default=(),
significant=False,
description="comma-separated list of files or directories relative to CMSSW_BASE to "
"include; default: empty",
)
custom_checksum = luigi.Parameter(
default=NO_STR,
description="a custom checksum to use; default: empty",
)
cmssw_checksumming = True
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self._checksum: str | None = None
@abc.abstractmethod
def get_cmssw_path(self) -> str | pathlib.Path | LocalFileTarget:
...
@property
def checksum(self) -> None | str:
if not self.cmssw_checksumming:
return None
if self.custom_checksum != NO_STR:
return self.custom_checksum # type: ignore[return-value]
if self._checksum is None:
cmd = [
rel_path(__file__, "scripts", "cmssw_checksum.sh"),
get_path(self.get_cmssw_path()),
]
if self.exclude != NO_STR:
cmd += [self.exclude] # type: ignore[list-item]
_cmd = quote_cmd(cmd)
out: str
code, out, _ = interruptable_popen( # type: ignore[assignment]
_cmd,
shell=True,
executable="/bin/bash",
stdout=subprocess.PIPE,
)
if code != 0:
raise Exception("cmssw checksum calculation failed")
self._checksum = out.strip()
return self._checksum
[docs]
def output(self) -> FileSystemFileTarget:
base = os.path.basename(get_path(self.get_cmssw_path()))
if self.checksum:
base += f"{self.checksum}."
base = os.path.abspath(os.path.expandvars(os.path.expanduser(base)))
return LocalFileTarget(f"{base}.tgz")
[docs]
@log
def run(self) -> None:
with self.output().localize("w") as tmp:
with self.publish_step("bundle CMSSW ..."):
self.bundle(tmp.path)
def get_cmssw_bundle_command(self, dst_path: str | pathlib.Path | LocalFileTarget) -> list[str]:
return [
rel_path(__file__, "scripts", "bundle_cmssw.sh"),
get_path(self.get_cmssw_path()),
get_path(dst_path),
self.exclude if self.exclude not in (None, NO_STR) else "", # type: ignore[list-item]
" ".join(self.include), # type: ignore[arg-type]
]
def bundle(self, dst_path: str | pathlib.Path | LocalFileTarget) -> None:
cmd = self.get_cmssw_bundle_command(dst_path)
code = interruptable_popen(quote_cmd(cmd), shell=True, executable="/bin/bash")[0]
if code != 0:
raise Exception("cmssw bundling failed")