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