xref: /OK3568_Linux_fs/yocto/poky/bitbake/lib/bb/fetch2/clearcase.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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