1*4882a593Smuzhiyun""" 2*4882a593SmuzhiyunBitBake 'Fetch' clearcase implementation 3*4882a593Smuzhiyun 4*4882a593SmuzhiyunThe clearcase fetcher is used to retrieve files from a ClearCase repository. 5*4882a593Smuzhiyun 6*4882a593SmuzhiyunUsage in the recipe: 7*4882a593Smuzhiyun 8*4882a593Smuzhiyun SRC_URI = "ccrc://cc.example.org/ccrc;vob=/example_vob;module=/example_module" 9*4882a593Smuzhiyun SRCREV = "EXAMPLE_CLEARCASE_TAG" 10*4882a593Smuzhiyun PV = "${@d.getVar("SRCREV", False).replace("/", "+")}" 11*4882a593Smuzhiyun 12*4882a593SmuzhiyunThe fetcher uses the rcleartool or cleartool remote client, depending on which one is available. 13*4882a593Smuzhiyun 14*4882a593SmuzhiyunSupported SRC_URI options are: 15*4882a593Smuzhiyun 16*4882a593Smuzhiyun- vob 17*4882a593Smuzhiyun (required) The name of the clearcase VOB (with prepending "/") 18*4882a593Smuzhiyun 19*4882a593Smuzhiyun- module 20*4882a593Smuzhiyun The module in the selected VOB (with prepending "/") 21*4882a593Smuzhiyun 22*4882a593Smuzhiyun The module and vob parameters are combined to create 23*4882a593Smuzhiyun the following load rule in the view config spec: 24*4882a593Smuzhiyun load <vob><module> 25*4882a593Smuzhiyun 26*4882a593Smuzhiyun- proto 27*4882a593Smuzhiyun http or https 28*4882a593Smuzhiyun 29*4882a593SmuzhiyunRelated variables: 30*4882a593Smuzhiyun 31*4882a593Smuzhiyun CCASE_CUSTOM_CONFIG_SPEC 32*4882a593Smuzhiyun Write a config spec to this variable in your recipe to use it instead 33*4882a593Smuzhiyun of the default config spec generated by this fetcher. 34*4882a593Smuzhiyun Please note that the SRCREV loses its functionality if you specify 35*4882a593Smuzhiyun this variable. SRCREV is still used to label the archive after a fetch, 36*4882a593Smuzhiyun but it doesn't define what's fetched. 37*4882a593Smuzhiyun 38*4882a593SmuzhiyunUser credentials: 39*4882a593Smuzhiyun cleartool: 40*4882a593Smuzhiyun The login of cleartool is handled by the system. No special steps needed. 41*4882a593Smuzhiyun 42*4882a593Smuzhiyun rcleartool: 43*4882a593Smuzhiyun In order to use rcleartool with authenticated users an `rcleartool login` is 44*4882a593Smuzhiyun necessary before using the fetcher. 45*4882a593Smuzhiyun""" 46*4882a593Smuzhiyun# Copyright (C) 2014 Siemens AG 47*4882a593Smuzhiyun# 48*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only 49*4882a593Smuzhiyun# 50*4882a593Smuzhiyun 51*4882a593Smuzhiyunimport os 52*4882a593Smuzhiyunimport shutil 53*4882a593Smuzhiyunimport bb 54*4882a593Smuzhiyunfrom bb.fetch2 import FetchMethod 55*4882a593Smuzhiyunfrom bb.fetch2 import FetchError 56*4882a593Smuzhiyunfrom bb.fetch2 import MissingParameterError 57*4882a593Smuzhiyunfrom bb.fetch2 import ParameterError 58*4882a593Smuzhiyunfrom bb.fetch2 import runfetchcmd 59*4882a593Smuzhiyunfrom bb.fetch2 import logger 60*4882a593Smuzhiyun 61*4882a593Smuzhiyunclass ClearCase(FetchMethod): 62*4882a593Smuzhiyun """Class to fetch urls via 'clearcase'""" 63*4882a593Smuzhiyun def init(self, d): 64*4882a593Smuzhiyun pass 65*4882a593Smuzhiyun 66*4882a593Smuzhiyun def supports(self, ud, d): 67*4882a593Smuzhiyun """ 68*4882a593Smuzhiyun Check to see if a given url can be fetched with Clearcase. 69*4882a593Smuzhiyun """ 70*4882a593Smuzhiyun return ud.type in ['ccrc'] 71*4882a593Smuzhiyun 72*4882a593Smuzhiyun def debug(self, msg): 73*4882a593Smuzhiyun logger.debug("ClearCase: %s", msg) 74*4882a593Smuzhiyun 75*4882a593Smuzhiyun def urldata_init(self, ud, d): 76*4882a593Smuzhiyun """ 77*4882a593Smuzhiyun init ClearCase specific variable within url data 78*4882a593Smuzhiyun """ 79*4882a593Smuzhiyun ud.proto = "https" 80*4882a593Smuzhiyun if 'protocol' in ud.parm: 81*4882a593Smuzhiyun ud.proto = ud.parm['protocol'] 82*4882a593Smuzhiyun if not ud.proto in ('http', 'https'): 83*4882a593Smuzhiyun raise ParameterError("Invalid protocol type", ud.url) 84*4882a593Smuzhiyun 85*4882a593Smuzhiyun ud.vob = '' 86*4882a593Smuzhiyun if 'vob' in ud.parm: 87*4882a593Smuzhiyun ud.vob = ud.parm['vob'] 88*4882a593Smuzhiyun else: 89*4882a593Smuzhiyun msg = ud.url+": vob must be defined so the fetcher knows what to get." 90*4882a593Smuzhiyun raise MissingParameterError('vob', msg) 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun if 'module' in ud.parm: 93*4882a593Smuzhiyun ud.module = ud.parm['module'] 94*4882a593Smuzhiyun else: 95*4882a593Smuzhiyun ud.module = "" 96*4882a593Smuzhiyun 97*4882a593Smuzhiyun ud.basecmd = d.getVar("FETCHCMD_ccrc") or "/usr/bin/env cleartool || rcleartool" 98*4882a593Smuzhiyun 99*4882a593Smuzhiyun if d.getVar("SRCREV") == "INVALID": 100*4882a593Smuzhiyun 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.") 101*4882a593Smuzhiyun 102*4882a593Smuzhiyun ud.label = d.getVar("SRCREV", False) 103*4882a593Smuzhiyun ud.customspec = d.getVar("CCASE_CUSTOM_CONFIG_SPEC") 104*4882a593Smuzhiyun 105*4882a593Smuzhiyun ud.server = "%s://%s%s" % (ud.proto, ud.host, ud.path) 106*4882a593Smuzhiyun 107*4882a593Smuzhiyun ud.identifier = "clearcase-%s%s-%s" % ( ud.vob.replace("/", ""), 108*4882a593Smuzhiyun ud.module.replace("/", "."), 109*4882a593Smuzhiyun ud.label.replace("/", ".")) 110*4882a593Smuzhiyun 111*4882a593Smuzhiyun ud.viewname = "%s-view%s" % (ud.identifier, d.getVar("DATETIME", d, True)) 112*4882a593Smuzhiyun ud.csname = "%s-config-spec" % (ud.identifier) 113*4882a593Smuzhiyun ud.ccasedir = os.path.join(d.getVar("DL_DIR"), ud.type) 114*4882a593Smuzhiyun ud.viewdir = os.path.join(ud.ccasedir, ud.viewname) 115*4882a593Smuzhiyun ud.configspecfile = os.path.join(ud.ccasedir, ud.csname) 116*4882a593Smuzhiyun ud.localfile = "%s.tar.gz" % (ud.identifier) 117*4882a593Smuzhiyun 118*4882a593Smuzhiyun self.debug("host = %s" % ud.host) 119*4882a593Smuzhiyun self.debug("path = %s" % ud.path) 120*4882a593Smuzhiyun self.debug("server = %s" % ud.server) 121*4882a593Smuzhiyun self.debug("proto = %s" % ud.proto) 122*4882a593Smuzhiyun self.debug("type = %s" % ud.type) 123*4882a593Smuzhiyun self.debug("vob = %s" % ud.vob) 124*4882a593Smuzhiyun self.debug("module = %s" % ud.module) 125*4882a593Smuzhiyun self.debug("basecmd = %s" % ud.basecmd) 126*4882a593Smuzhiyun self.debug("label = %s" % ud.label) 127*4882a593Smuzhiyun self.debug("ccasedir = %s" % ud.ccasedir) 128*4882a593Smuzhiyun self.debug("viewdir = %s" % ud.viewdir) 129*4882a593Smuzhiyun self.debug("viewname = %s" % ud.viewname) 130*4882a593Smuzhiyun self.debug("configspecfile = %s" % ud.configspecfile) 131*4882a593Smuzhiyun self.debug("localfile = %s" % ud.localfile) 132*4882a593Smuzhiyun 133*4882a593Smuzhiyun ud.localfile = os.path.join(d.getVar("DL_DIR"), ud.localfile) 134*4882a593Smuzhiyun 135*4882a593Smuzhiyun def _build_ccase_command(self, ud, command): 136*4882a593Smuzhiyun """ 137*4882a593Smuzhiyun Build up a commandline based on ud 138*4882a593Smuzhiyun command is: mkview, setcs, rmview 139*4882a593Smuzhiyun """ 140*4882a593Smuzhiyun options = [] 141*4882a593Smuzhiyun 142*4882a593Smuzhiyun if "rcleartool" in ud.basecmd: 143*4882a593Smuzhiyun options.append("-server %s" % ud.server) 144*4882a593Smuzhiyun 145*4882a593Smuzhiyun basecmd = "%s %s" % (ud.basecmd, command) 146*4882a593Smuzhiyun 147*4882a593Smuzhiyun if command == 'mkview': 148*4882a593Smuzhiyun if not "rcleartool" in ud.basecmd: 149*4882a593Smuzhiyun # Cleartool needs a -snapshot view 150*4882a593Smuzhiyun options.append("-snapshot") 151*4882a593Smuzhiyun options.append("-tag %s" % ud.viewname) 152*4882a593Smuzhiyun options.append(ud.viewdir) 153*4882a593Smuzhiyun 154*4882a593Smuzhiyun elif command == 'rmview': 155*4882a593Smuzhiyun options.append("-force") 156*4882a593Smuzhiyun options.append("%s" % ud.viewdir) 157*4882a593Smuzhiyun 158*4882a593Smuzhiyun elif command == 'setcs': 159*4882a593Smuzhiyun options.append("-overwrite") 160*4882a593Smuzhiyun options.append(ud.configspecfile) 161*4882a593Smuzhiyun 162*4882a593Smuzhiyun else: 163*4882a593Smuzhiyun raise FetchError("Invalid ccase command %s" % command) 164*4882a593Smuzhiyun 165*4882a593Smuzhiyun ccasecmd = "%s %s" % (basecmd, " ".join(options)) 166*4882a593Smuzhiyun self.debug("ccasecmd = %s" % ccasecmd) 167*4882a593Smuzhiyun return ccasecmd 168*4882a593Smuzhiyun 169*4882a593Smuzhiyun def _write_configspec(self, ud, d): 170*4882a593Smuzhiyun """ 171*4882a593Smuzhiyun Create config spec file (ud.configspecfile) for ccase view 172*4882a593Smuzhiyun """ 173*4882a593Smuzhiyun config_spec = "" 174*4882a593Smuzhiyun custom_config_spec = d.getVar("CCASE_CUSTOM_CONFIG_SPEC", d) 175*4882a593Smuzhiyun if custom_config_spec is not None: 176*4882a593Smuzhiyun for line in custom_config_spec.split("\\n"): 177*4882a593Smuzhiyun config_spec += line+"\n" 178*4882a593Smuzhiyun bb.warn("A custom config spec has been set, SRCREV is only relevant for the tarball name.") 179*4882a593Smuzhiyun else: 180*4882a593Smuzhiyun config_spec += "element * CHECKEDOUT\n" 181*4882a593Smuzhiyun config_spec += "element * %s\n" % ud.label 182*4882a593Smuzhiyun config_spec += "load %s%s\n" % (ud.vob, ud.module) 183*4882a593Smuzhiyun 184*4882a593Smuzhiyun logger.info("Using config spec: \n%s" % config_spec) 185*4882a593Smuzhiyun 186*4882a593Smuzhiyun with open(ud.configspecfile, 'w') as f: 187*4882a593Smuzhiyun f.write(config_spec) 188*4882a593Smuzhiyun 189*4882a593Smuzhiyun def _remove_view(self, ud, d): 190*4882a593Smuzhiyun if os.path.exists(ud.viewdir): 191*4882a593Smuzhiyun cmd = self._build_ccase_command(ud, 'rmview'); 192*4882a593Smuzhiyun logger.info("cleaning up [VOB=%s label=%s view=%s]", ud.vob, ud.label, ud.viewname) 193*4882a593Smuzhiyun bb.fetch2.check_network_access(d, cmd, ud.url) 194*4882a593Smuzhiyun output = runfetchcmd(cmd, d, workdir=ud.ccasedir) 195*4882a593Smuzhiyun logger.info("rmview output: %s", output) 196*4882a593Smuzhiyun 197*4882a593Smuzhiyun def need_update(self, ud, d): 198*4882a593Smuzhiyun if ("LATEST" in ud.label) or (ud.customspec and "LATEST" in ud.customspec): 199*4882a593Smuzhiyun ud.identifier += "-%s" % d.getVar("DATETIME",d, True) 200*4882a593Smuzhiyun return True 201*4882a593Smuzhiyun if os.path.exists(ud.localpath): 202*4882a593Smuzhiyun return False 203*4882a593Smuzhiyun return True 204*4882a593Smuzhiyun 205*4882a593Smuzhiyun def supports_srcrev(self): 206*4882a593Smuzhiyun return True 207*4882a593Smuzhiyun 208*4882a593Smuzhiyun def sortable_revision(self, ud, d, name): 209*4882a593Smuzhiyun return False, ud.identifier 210*4882a593Smuzhiyun 211*4882a593Smuzhiyun def download(self, ud, d): 212*4882a593Smuzhiyun """Fetch url""" 213*4882a593Smuzhiyun 214*4882a593Smuzhiyun # Make a fresh view 215*4882a593Smuzhiyun bb.utils.mkdirhier(ud.ccasedir) 216*4882a593Smuzhiyun self._write_configspec(ud, d) 217*4882a593Smuzhiyun cmd = self._build_ccase_command(ud, 'mkview') 218*4882a593Smuzhiyun logger.info("creating view [VOB=%s label=%s view=%s]", ud.vob, ud.label, ud.viewname) 219*4882a593Smuzhiyun bb.fetch2.check_network_access(d, cmd, ud.url) 220*4882a593Smuzhiyun try: 221*4882a593Smuzhiyun runfetchcmd(cmd, d) 222*4882a593Smuzhiyun except FetchError as e: 223*4882a593Smuzhiyun if "CRCLI2008E" in e.msg: 224*4882a593Smuzhiyun raise FetchError("%s\n%s\n" % (e.msg, "Call `rcleartool login` in your console to authenticate to the clearcase server before running bitbake.")) 225*4882a593Smuzhiyun else: 226*4882a593Smuzhiyun raise e 227*4882a593Smuzhiyun 228*4882a593Smuzhiyun # Set configspec: Setting the configspec effectively fetches the files as defined in the configspec 229*4882a593Smuzhiyun cmd = self._build_ccase_command(ud, 'setcs'); 230*4882a593Smuzhiyun logger.info("fetching data [VOB=%s label=%s view=%s]", ud.vob, ud.label, ud.viewname) 231*4882a593Smuzhiyun bb.fetch2.check_network_access(d, cmd, ud.url) 232*4882a593Smuzhiyun output = runfetchcmd(cmd, d, workdir=ud.viewdir) 233*4882a593Smuzhiyun logger.info("%s", output) 234*4882a593Smuzhiyun 235*4882a593Smuzhiyun # Copy the configspec to the viewdir so we have it in our source tarball later 236*4882a593Smuzhiyun shutil.copyfile(ud.configspecfile, os.path.join(ud.viewdir, ud.csname)) 237*4882a593Smuzhiyun 238*4882a593Smuzhiyun # Clean clearcase meta-data before tar 239*4882a593Smuzhiyun 240*4882a593Smuzhiyun runfetchcmd('tar -czf "%s" .' % (ud.localpath), d, cleanup = [ud.localpath], workdir = ud.viewdir) 241*4882a593Smuzhiyun 242*4882a593Smuzhiyun # Clean up so we can create a new view next time 243*4882a593Smuzhiyun self.clean(ud, d); 244*4882a593Smuzhiyun 245*4882a593Smuzhiyun def clean(self, ud, d): 246*4882a593Smuzhiyun self._remove_view(ud, d) 247*4882a593Smuzhiyun bb.utils.remove(ud.configspecfile) 248