blob: 54d001ec81dbd91b98a24d130213e6144e95f7c6 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001"""
Patrick Williamsc0f7c042017-02-23 20:41:17 -06002BitBake 'Fetch' implementation for perforce
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003
4"""
5
6# Copyright (C) 2003, 2004 Chris Larson
Patrick Williamsc0f7c042017-02-23 20:41:17 -06007# Copyright (C) 2016 Kodak Alaris, Inc.
Patrick Williamsc124f4f2015-09-15 14:41:29 -05008#
Brad Bishopc342db32019-05-15 21:57:59 -04009# SPDX-License-Identifier: GPL-2.0-only
Patrick Williamsc124f4f2015-09-15 14:41:29 -050010#
11# Based on functions from the base bb module, Copyright 2003 Holger Schurig
12
Patrick Williamsc124f4f2015-09-15 14:41:29 -050013import os
Patrick Williamsc124f4f2015-09-15 14:41:29 -050014import logging
15import bb
Patrick Williamsc124f4f2015-09-15 14:41:29 -050016from bb.fetch2 import FetchMethod
17from bb.fetch2 import FetchError
18from bb.fetch2 import logger
19from bb.fetch2 import runfetchcmd
20
21class Perforce(FetchMethod):
Patrick Williamsc0f7c042017-02-23 20:41:17 -060022 """ Class to fetch from perforce repositories """
Patrick Williamsc124f4f2015-09-15 14:41:29 -050023 def supports(self, ud, d):
Patrick Williamsc0f7c042017-02-23 20:41:17 -060024 """ Check to see if a given url can be fetched with perforce. """
Patrick Williamsc124f4f2015-09-15 14:41:29 -050025 return ud.type in ['p4']
26
Patrick Williamsc124f4f2015-09-15 14:41:29 -050027 def urldata_init(self, ud, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050028 """
Patrick Williamsc0f7c042017-02-23 20:41:17 -060029 Initialize perforce specific variables within url data. If P4CONFIG is
30 provided by the env, use it. If P4PORT is specified by the recipe, use
31 its values, which may override the settings in P4CONFIG.
Patrick Williamsc124f4f2015-09-15 14:41:29 -050032 """
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080033 ud.basecmd = d.getVar("FETCHCMD_p4") or "/usr/bin/env p4"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050034
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080035 ud.dldir = d.getVar("P4DIR") or (d.getVar("DL_DIR") + "/p4")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050036
Patrick Williamsc0f7c042017-02-23 20:41:17 -060037 path = ud.url.split('://')[1]
38 path = path.split(';')[0]
39 delim = path.find('@');
40 if delim != -1:
41 (ud.user, ud.pswd) = path.split('@')[0].split(':')
42 ud.path = path.split('@')[1]
Patrick Williamsc124f4f2015-09-15 14:41:29 -050043 else:
Patrick Williamsc0f7c042017-02-23 20:41:17 -060044 ud.path = path
Patrick Williamsc124f4f2015-09-15 14:41:29 -050045
Patrick Williamsc0f7c042017-02-23 20:41:17 -060046 ud.usingp4config = False
Brad Bishop6e60e8b2018-02-01 10:27:11 -050047 p4port = d.getVar('P4PORT')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050048
Patrick Williamsc0f7c042017-02-23 20:41:17 -060049 if p4port:
50 logger.debug(1, 'Using recipe provided P4PORT: %s' % p4port)
51 ud.host = p4port
52 else:
53 logger.debug(1, 'Trying to use P4CONFIG to automatically set P4PORT...')
54 ud.usingp4config = True
55 p4cmd = '%s info | grep "Server address"' % ud.basecmd
Brad Bishop6e60e8b2018-02-01 10:27:11 -050056 bb.fetch2.check_network_access(d, p4cmd, ud.url)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060057 ud.host = runfetchcmd(p4cmd, d, True)
58 ud.host = ud.host.split(': ')[1].strip()
59 logger.debug(1, 'Determined P4PORT to be: %s' % ud.host)
60 if not ud.host:
61 raise FetchError('Could not determine P4PORT from P4CONFIG')
62
63 if ud.path.find('/...') >= 0:
64 ud.pathisdir = True
65 else:
66 ud.pathisdir = False
67
68 cleanedpath = ud.path.replace('/...', '').replace('/', '.')
69 cleanedhost = ud.host.replace(':', '.')
70 ud.pkgdir = os.path.join(ud.dldir, cleanedhost, cleanedpath)
71
Brad Bishop6e60e8b2018-02-01 10:27:11 -050072 ud.setup_revisions(d)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060073
Brad Bishop6e60e8b2018-02-01 10:27:11 -050074 ud.localfile = d.expand('%s_%s_%s.tar.gz' % (cleanedhost, cleanedpath, ud.revision))
Patrick Williamsc0f7c042017-02-23 20:41:17 -060075
76 def _buildp4command(self, ud, d, command, depot_filename=None):
77 """
78 Build a p4 commandline. Valid commands are "changes", "print", and
79 "files". depot_filename is the full path to the file in the depot
80 including the trailing '#rev' value.
81 """
Patrick Williamsc124f4f2015-09-15 14:41:29 -050082 p4opt = ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -050083
Patrick Williamsc0f7c042017-02-23 20:41:17 -060084 if ud.user:
85 p4opt += ' -u "%s"' % (ud.user)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050086
Patrick Williamsc0f7c042017-02-23 20:41:17 -060087 if ud.pswd:
88 p4opt += ' -P "%s"' % (ud.pswd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050089
Patrick Williamsc0f7c042017-02-23 20:41:17 -060090 if ud.host and not ud.usingp4config:
91 p4opt += ' -p %s' % (ud.host)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050092
Patrick Williamsc0f7c042017-02-23 20:41:17 -060093 if hasattr(ud, 'revision') and ud.revision:
94 pathnrev = '%s@%s' % (ud.path, ud.revision)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050095 else:
Patrick Williamsc0f7c042017-02-23 20:41:17 -060096 pathnrev = '%s' % (ud.path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050097
Patrick Williamsc0f7c042017-02-23 20:41:17 -060098 if depot_filename:
99 if ud.pathisdir: # Remove leading path to obtain filename
100 filename = depot_filename[len(ud.path)-1:]
101 else:
102 filename = depot_filename[depot_filename.rfind('/'):]
103 filename = filename[:filename.find('#')] # Remove trailing '#rev'
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500104
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600105 if command == 'changes':
106 p4cmd = '%s%s changes -m 1 //%s' % (ud.basecmd, p4opt, pathnrev)
107 elif command == 'print':
108 if depot_filename != None:
109 p4cmd = '%s%s print -o "p4/%s" "%s"' % (ud.basecmd, p4opt, filename, depot_filename)
110 else:
111 raise FetchError('No depot file name provided to p4 %s' % command, ud.url)
112 elif command == 'files':
113 p4cmd = '%s%s files //%s' % (ud.basecmd, p4opt, pathnrev)
114 else:
115 raise FetchError('Invalid p4 command %s' % command, ud.url)
116
117 return p4cmd
118
119 def _p4listfiles(self, ud, d):
120 """
121 Return a list of the file names which are present in the depot using the
122 'p4 files' command, including trailing '#rev' file revision indicator
123 """
124 p4cmd = self._buildp4command(ud, d, 'files')
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500125 bb.fetch2.check_network_access(d, p4cmd, ud.url)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600126 p4fileslist = runfetchcmd(p4cmd, d, True)
127 p4fileslist = [f.rstrip() for f in p4fileslist.splitlines()]
128
129 if not p4fileslist:
130 raise FetchError('Unable to fetch listing of p4 files from %s@%s' % (ud.host, ud.path))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500131
132 count = 0
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600133 filelist = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500134
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600135 for filename in p4fileslist:
136 item = filename.split(' - ')
137 lastaction = item[1].split()
138 logger.debug(1, 'File: %s Last Action: %s' % (item[0], lastaction[0]))
139 if lastaction[0] == 'delete':
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500140 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600141 filelist.append(item[0])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500142
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600143 return filelist
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500144
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600145 def download(self, ud, d):
146 """ Get the list of files, fetch each one """
147 filelist = self._p4listfiles(ud, d)
148 if not filelist:
149 raise FetchError('No files found in depot %s@%s' % (ud.host, ud.path))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500150
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600151 bb.utils.remove(ud.pkgdir, True)
152 bb.utils.mkdirhier(ud.pkgdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500153
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600154 for afile in filelist:
155 p4fetchcmd = self._buildp4command(ud, d, 'print', afile)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500156 bb.fetch2.check_network_access(d, p4fetchcmd, ud.url)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600157 runfetchcmd(p4fetchcmd, d, workdir=ud.pkgdir)
158
159 runfetchcmd('tar -czf %s p4' % (ud.localpath), d, cleanup=[ud.localpath], workdir=ud.pkgdir)
160
161 def clean(self, ud, d):
162 """ Cleanup p4 specific files and dirs"""
163 bb.utils.remove(ud.localpath)
164 bb.utils.remove(ud.pkgdir, True)
165
166 def supports_srcrev(self):
167 return True
168
169 def _revision_key(self, ud, d, name):
170 """ Return a unique key for the url """
171 return 'p4:%s' % ud.pkgdir
172
173 def _latest_revision(self, ud, d, name):
174 """ Return the latest upstream scm revision number """
175 p4cmd = self._buildp4command(ud, d, "changes")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500176 bb.fetch2.check_network_access(d, p4cmd, ud.url)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600177 tip = runfetchcmd(p4cmd, d, True)
178
179 if not tip:
180 raise FetchError('Could not determine the latest perforce changelist')
181
182 tipcset = tip.split(' ')[1]
183 logger.debug(1, 'p4 tip found to be changelist %s' % tipcset)
184 return tipcset
185
186 def sortable_revision(self, ud, d, name):
187 """ Return a sortable revision number """
188 return False, self._build_revision(ud, d)
189
190 def _build_revision(self, ud, d):
191 return ud.revision
192