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")) 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 def _build_ccase_command(self, ud, command): 134 """ 135 Build up a commandline based on ud 136 command is: mkview, setcs, rmview 137 """ 138 options = [] 139 140 if "rcleartool" in ud.basecmd: 141 options.append("-server %s" % ud.server) 142 143 basecmd = "%s %s" % (ud.basecmd, command) 144 145 if command == 'mkview': 146 if not "rcleartool" in ud.basecmd: 147 # Cleartool needs a -snapshot view 148 options.append("-snapshot") 149 options.append("-tag %s" % ud.viewname) 150 options.append(ud.viewdir) 151 152 elif command == 'rmview': 153 options.append("-force") 154 options.append("%s" % ud.viewdir) 155 156 elif command == 'setcs': 157 options.append("-overwrite") 158 options.append(ud.configspecfile) 159 160 else: 161 raise FetchError("Invalid ccase command %s" % command) 162 163 ccasecmd = "%s %s" % (basecmd, " ".join(options)) 164 self.debug("ccasecmd = %s" % ccasecmd) 165 return ccasecmd 166 167 def _write_configspec(self, ud, d): 168 """ 169 Create config spec file (ud.configspecfile) for ccase view 170 """ 171 config_spec = "" 172 custom_config_spec = d.getVar("CCASE_CUSTOM_CONFIG_SPEC", d) 173 if custom_config_spec is not None: 174 for line in custom_config_spec.split("\\n"): 175 config_spec += line+"\n" 176 bb.warn("A custom config spec has been set, SRCREV is only relevant for the tarball name.") 177 else: 178 config_spec += "element * CHECKEDOUT\n" 179 config_spec += "element * %s\n" % ud.label 180 config_spec += "load %s%s\n" % (ud.vob, ud.module) 181 182 logger.info("Using config spec: \n%s" % config_spec) 183 184 with open(ud.configspecfile, 'w') as f: 185 f.write(config_spec) 186 187 def _remove_view(self, ud, d): 188 if os.path.exists(ud.viewdir): 189 cmd = self._build_ccase_command(ud, 'rmview'); 190 logger.info("cleaning up [VOB=%s label=%s view=%s]", ud.vob, ud.label, ud.viewname) 191 bb.fetch2.check_network_access(d, cmd, ud.url) 192 output = runfetchcmd(cmd, d, workdir=ud.ccasedir) 193 logger.info("rmview output: %s", output) 194 195 def need_update(self, ud, d): 196 if ("LATEST" in ud.label) or (ud.customspec and "LATEST" in ud.customspec): 197 ud.identifier += "-%s" % d.getVar("DATETIME") 198 return True 199 if os.path.exists(ud.localpath): 200 return False 201 return True 202 203 def supports_srcrev(self): 204 return True 205 206 def sortable_revision(self, ud, d, name): 207 return False, ud.identifier 208 209 def download(self, ud, d): 210 """Fetch url""" 211 212 # Make a fresh view 213 bb.utils.mkdirhier(ud.ccasedir) 214 self._write_configspec(ud, d) 215 cmd = self._build_ccase_command(ud, 'mkview') 216 logger.info("creating view [VOB=%s label=%s view=%s]", ud.vob, ud.label, ud.viewname) 217 bb.fetch2.check_network_access(d, cmd, ud.url) 218 try: 219 runfetchcmd(cmd, d) 220 except FetchError as e: 221 if "CRCLI2008E" in e.msg: 222 raise FetchError("%s\n%s\n" % (e.msg, "Call `rcleartool login` in your console to authenticate to the clearcase server before running bitbake.")) 223 else: 224 raise e 225 226 # Set configspec: Setting the configspec effectively fetches the files as defined in the configspec 227 cmd = self._build_ccase_command(ud, 'setcs'); 228 logger.info("fetching data [VOB=%s label=%s view=%s]", ud.vob, ud.label, ud.viewname) 229 bb.fetch2.check_network_access(d, cmd, ud.url) 230 output = runfetchcmd(cmd, d, workdir=ud.viewdir) 231 logger.info("%s", output) 232 233 # Copy the configspec to the viewdir so we have it in our source tarball later 234 shutil.copyfile(ud.configspecfile, os.path.join(ud.viewdir, ud.csname)) 235 236 # Clean clearcase meta-data before tar 237 238 runfetchcmd('tar -czf "%s" .' % (ud.localpath), d, cleanup = [ud.localpath], workdir = ud.viewdir) 239 240 # Clean up so we can create a new view next time 241 self.clean(ud, d); 242 243 def clean(self, ud, d): 244 self._remove_view(ud, d) 245 bb.utils.remove(ud.configspecfile) 246