diff --git a/lib/bb/fetch2/__init__.py b/lib/bb/fetch2/__init__.py index dcada12ead..df2f2b056b 100644 --- a/lib/bb/fetch2/__init__.py +++ b/lib/bb/fetch2/__init__.py @@ -1560,6 +1560,7 @@ def clean(self, urls = []): from . import hg from . import osc from . import repo +from . import clearcase methods.append(local.Local()) methods.append(wget.Wget()) @@ -1575,3 +1576,4 @@ def clean(self, urls = []): methods.append(hg.Hg()) methods.append(osc.Osc()) methods.append(repo.Repo()) +methods.append(clearcase.ClearCase()) diff --git a/lib/bb/fetch2/clearcase.py b/lib/bb/fetch2/clearcase.py new file mode 100644 index 0000000000..bfca2f7bcf --- /dev/null +++ b/lib/bb/fetch2/clearcase.py @@ -0,0 +1,263 @@ +# ex:ts=4:sw=4:sts=4:et +# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +""" +BitBake 'Fetch' clearcase implementation + +The clearcase fetcher is used to retrieve files from a ClearCase repository. + +Usage in the recipe: + + SRC_URI = "ccrc://cc.example.org/ccrc;vob=/example_vob;module=/example_module" + SRCREV = "EXAMPLE_CLEARCASE_TAG" + PV = "${@d.getVar("SRCREV").replace("/", "+")}" + +The fetcher uses the rcleartool or cleartool remote client, depending on which one is available. + +Supported SRC_URI options are: + +- vob + (required) The name of the clearcase VOB (with prepending "/") + +- module + The module in the selected VOB (with prepending "/") + + The module and vob parameters are combined to create + the following load rule in the view config spec: + load + +- proto + http or https + +Related variables: + + CCASE_CUSTOM_CONFIG_SPEC + Write a config spec to this variable in your recipe to use it instead + of the default config spec generated by this fetcher. + Please note that the SRCREV loses its functionality if you specify + this variable. SRCREV is still used to label the archive after a fetch, + but it doesn't define what's fetched. + +User credentials: + cleartool: + The login of cleartool is handled by the system. No special steps needed. + + rcleartool: + In order to use rcleartool with authenticated users an `rcleartool login` is + necessary before using the fetcher. +""" +# Copyright (C) 2014 Siemens AG +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program 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 this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +import os +import sys +import shutil +import bb +from bb import data +from bb.fetch2 import FetchMethod +from bb.fetch2 import FetchError +from bb.fetch2 import runfetchcmd +from bb.fetch2 import logger +from distutils import spawn + +class ClearCase(FetchMethod): + """Class to fetch urls via 'clearcase'""" + def init(self, d): + pass + + def supports(self, ud, d): + """ + Check to see if a given url can be fetched with Clearcase. + """ + return ud.type in ['ccrc'] + + def debug(self, msg): + logger.debug(1, "ClearCase: %s", msg) + + def urldata_init(self, ud, d): + """ + init ClearCase specific variable within url data + """ + ud.proto = "https" + if 'protocol' in ud.parm: + ud.proto = ud.parm['protocol'] + if not ud.proto in ('http', 'https'): + raise fetch2.ParameterError("Invalid protocol type", ud.url) + + ud.vob = '' + if 'vob' in ud.parm: + ud.vob = ud.parm['vob'] + else: + msg = ud.url+": vob must be defined so the fetcher knows what to get." + raise MissingParameterError('vob', msg) + + if 'module' in ud.parm: + ud.module = ud.parm['module'] + else: + ud.module = "" + + ud.basecmd = d.getVar("FETCHCMD_ccrc", True) or spawn.find_executable("cleartool") or spawn.find_executable("rcleartool") + + if data.getVar("SRCREV", d, True) == "INVALID": + raise FetchError("Set a valid SRCREV for the clearcase fetcher in your recipe, e.g. SRCREV = \"/main/LATEST\" or any other label of your choice.") + + ud.label = d.getVar("SRCREV") + ud.customspec = d.getVar("CCASE_CUSTOM_CONFIG_SPEC", True) + + ud.server = "%s://%s%s" % (ud.proto, ud.host, ud.path) + + ud.identifier = "clearcase-%s%s-%s" % ( ud.vob.replace("/", ""), + ud.module.replace("/", "."), + ud.label.replace("/", ".")) + + ud.viewname = "%s-view%s" % (ud.identifier, d.getVar("DATETIME", d, True)) + ud.csname = "%s-config-spec" % (ud.identifier) + ud.ccasedir = os.path.join(data.getVar("DL_DIR", d, True), ud.type) + ud.viewdir = os.path.join(ud.ccasedir, ud.viewname) + ud.configspecfile = os.path.join(ud.ccasedir, ud.csname) + ud.localfile = "%s.tar.gz" % (ud.identifier) + + self.debug("host = %s" % ud.host) + self.debug("path = %s" % ud.path) + self.debug("server = %s" % ud.server) + self.debug("proto = %s" % ud.proto) + self.debug("type = %s" % ud.type) + self.debug("vob = %s" % ud.vob) + self.debug("module = %s" % ud.module) + self.debug("basecmd = %s" % ud.basecmd) + self.debug("label = %s" % ud.label) + self.debug("ccasedir = %s" % ud.ccasedir) + self.debug("viewdir = %s" % ud.viewdir) + self.debug("viewname = %s" % ud.viewname) + self.debug("configspecfile = %s" % ud.configspecfile) + self.debug("localfile = %s" % ud.localfile) + + ud.localfile = os.path.join(data.getVar("DL_DIR", d, True), ud.localfile) + + def _build_ccase_command(self, ud, command): + """ + Build up a commandline based on ud + command is: mkview, setcs, rmview + """ + options = [] + + if "rcleartool" in ud.basecmd: + options.append("-server %s" % ud.server) + + basecmd = "%s %s" % (ud.basecmd, command) + + if command is 'mkview': + if not "rcleartool" in ud.basecmd: + # Cleartool needs a -snapshot view + options.append("-snapshot") + options.append("-tag %s" % ud.viewname) + options.append(ud.viewdir) + + elif command is 'rmview': + options.append("-force") + options.append("%s" % ud.viewdir) + + elif command is 'setcs': + options.append("-overwrite") + options.append(ud.configspecfile) + + else: + raise FetchError("Invalid ccase command %s" % command) + + ccasecmd = "%s %s" % (basecmd, " ".join(options)) + self.debug("ccasecmd = %s" % ccasecmd) + return ccasecmd + + def _write_configspec(self, ud, d): + """ + Create config spec file (ud.configspecfile) for ccase view + """ + config_spec = "" + custom_config_spec = d.getVar("CCASE_CUSTOM_CONFIG_SPEC", d) + if custom_config_spec is not None: + for line in custom_config_spec.split("\\n"): + config_spec += line+"\n" + bb.warn("A custom config spec has been set, SRCREV is only relevant for the tarball name.") + else: + config_spec += "element * CHECKEDOUT\n" + config_spec += "element * %s\n" % ud.label + config_spec += "load %s%s\n" % (ud.vob, ud.module) + + logger.info("Using config spec: \n%s" % config_spec) + + with open(ud.configspecfile, 'w') as f: + f.write(config_spec) + + def _remove_view(self, ud, d): + if os.path.exists(ud.viewdir): + os.chdir(ud.ccasedir) + cmd = self._build_ccase_command(ud, 'rmview'); + logger.info("cleaning up [VOB=%s label=%s view=%s]", ud.vob, ud.label, ud.viewname) + bb.fetch2.check_network_access(d, cmd, ud.url) + output = runfetchcmd(cmd, d) + logger.info("rmview output: %s", output) + + def need_update(self, ud, d): + if ("LATEST" in ud.label) or (ud.customspec and "LATEST" in ud.customspec): + ud.identifier += "-%s" % d.getVar("DATETIME",d, True) + return True + if os.path.exists(ud.localpath): + return False + return True + + def supports_srcrev(self): + return True + + def sortable_revision(self, ud, d, name): + return False, ud.identifier + + def download(self, ud, d): + """Fetch url""" + + # Make a fresh view + bb.utils.mkdirhier(ud.ccasedir) + self._write_configspec(ud, d) + cmd = self._build_ccase_command(ud, 'mkview') + logger.info("creating view [VOB=%s label=%s view=%s]", ud.vob, ud.label, ud.viewname) + bb.fetch2.check_network_access(d, cmd, ud.url) + try: + runfetchcmd(cmd, d) + except FetchError as e: + if "CRCLI2008E" in e.msg: + raise FetchError("%s\n%s\n" % (e.msg, "Call `rcleartool login` in your console to authenticate to the clearcase server before running bitbake.")) + else: + raise e + + # Set configspec: Setting the configspec effectively fetches the files as defined in the configspec + os.chdir(ud.viewdir) + cmd = self._build_ccase_command(ud, 'setcs'); + logger.info("fetching data [VOB=%s label=%s view=%s]", ud.vob, ud.label, ud.viewname) + bb.fetch2.check_network_access(d, cmd, ud.url) + output = runfetchcmd(cmd, d) + logger.info("%s", output) + + # Copy the configspec to the viewdir so we have it in our source tarball later + shutil.copyfile(ud.configspecfile, os.path.join(ud.viewdir, ud.csname)) + + # Clean clearcase meta-data before tar + + runfetchcmd('tar -czf "%s" .' % (ud.localpath), d, cleanup = [ud.localpath]) + + # Clean up so we can create a new view next time + self.clean(ud, d); + + def clean(self, ud, d): + self._remove_view(ud, d) + bb.utils.remove(ud.configspecfile)