blob: 3debad59f48870c18e50c0280ff65ff2dc34f9b5 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3"""
Patrick Williamsc0f7c042017-02-23 20:41:17 -06004BitBake 'Fetch' implementation for perforce
Patrick Williamsc124f4f2015-09-15 14:41:29 -05005
6"""
7
8# Copyright (C) 2003, 2004 Chris Larson
Patrick Williamsc0f7c042017-02-23 20:41:17 -06009# Copyright (C) 2016 Kodak Alaris, Inc.
Patrick Williamsc124f4f2015-09-15 14:41:29 -050010#
11# This program is free software; you can redistribute it and/or modify
12# it under the terms of the GNU General Public License version 2 as
13# published by the Free Software Foundation.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License along
21# with this program; if not, write to the Free Software Foundation, Inc.,
22# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23#
24# Based on functions from the base bb module, Copyright 2003 Holger Schurig
25
Patrick Williamsc124f4f2015-09-15 14:41:29 -050026import os
Patrick Williamsc124f4f2015-09-15 14:41:29 -050027import logging
28import bb
Patrick Williamsc124f4f2015-09-15 14:41:29 -050029from bb.fetch2 import FetchMethod
30from bb.fetch2 import FetchError
31from bb.fetch2 import logger
32from bb.fetch2 import runfetchcmd
33
34class Perforce(FetchMethod):
Patrick Williamsc0f7c042017-02-23 20:41:17 -060035 """ Class to fetch from perforce repositories """
Patrick Williamsc124f4f2015-09-15 14:41:29 -050036 def supports(self, ud, d):
Patrick Williamsc0f7c042017-02-23 20:41:17 -060037 """ Check to see if a given url can be fetched with perforce. """
Patrick Williamsc124f4f2015-09-15 14:41:29 -050038 return ud.type in ['p4']
39
Patrick Williamsc124f4f2015-09-15 14:41:29 -050040 def urldata_init(self, ud, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050041 """
Patrick Williamsc0f7c042017-02-23 20:41:17 -060042 Initialize perforce specific variables within url data. If P4CONFIG is
43 provided by the env, use it. If P4PORT is specified by the recipe, use
44 its values, which may override the settings in P4CONFIG.
Patrick Williamsc124f4f2015-09-15 14:41:29 -050045 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -050046 ud.basecmd = d.getVar('FETCHCMD_p4')
Patrick Williamsc0f7c042017-02-23 20:41:17 -060047 if not ud.basecmd:
48 ud.basecmd = "/usr/bin/env p4"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050049
Brad Bishop6e60e8b2018-02-01 10:27:11 -050050 ud.dldir = d.getVar('P4DIR')
Patrick Williamsc0f7c042017-02-23 20:41:17 -060051 if not ud.dldir:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050052 ud.dldir = '%s/%s' % (d.getVar('DL_DIR'), 'p4')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050053
Patrick Williamsc0f7c042017-02-23 20:41:17 -060054 path = ud.url.split('://')[1]
55 path = path.split(';')[0]
56 delim = path.find('@');
57 if delim != -1:
58 (ud.user, ud.pswd) = path.split('@')[0].split(':')
59 ud.path = path.split('@')[1]
Patrick Williamsc124f4f2015-09-15 14:41:29 -050060 else:
Patrick Williamsc0f7c042017-02-23 20:41:17 -060061 ud.path = path
Patrick Williamsc124f4f2015-09-15 14:41:29 -050062
Patrick Williamsc0f7c042017-02-23 20:41:17 -060063 ud.usingp4config = False
Brad Bishop6e60e8b2018-02-01 10:27:11 -050064 p4port = d.getVar('P4PORT')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050065
Patrick Williamsc0f7c042017-02-23 20:41:17 -060066 if p4port:
67 logger.debug(1, 'Using recipe provided P4PORT: %s' % p4port)
68 ud.host = p4port
69 else:
70 logger.debug(1, 'Trying to use P4CONFIG to automatically set P4PORT...')
71 ud.usingp4config = True
72 p4cmd = '%s info | grep "Server address"' % ud.basecmd
Brad Bishop6e60e8b2018-02-01 10:27:11 -050073 bb.fetch2.check_network_access(d, p4cmd, ud.url)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060074 ud.host = runfetchcmd(p4cmd, d, True)
75 ud.host = ud.host.split(': ')[1].strip()
76 logger.debug(1, 'Determined P4PORT to be: %s' % ud.host)
77 if not ud.host:
78 raise FetchError('Could not determine P4PORT from P4CONFIG')
79
80 if ud.path.find('/...') >= 0:
81 ud.pathisdir = True
82 else:
83 ud.pathisdir = False
84
85 cleanedpath = ud.path.replace('/...', '').replace('/', '.')
86 cleanedhost = ud.host.replace(':', '.')
87 ud.pkgdir = os.path.join(ud.dldir, cleanedhost, cleanedpath)
88
Brad Bishop6e60e8b2018-02-01 10:27:11 -050089 ud.setup_revisions(d)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060090
Brad Bishop6e60e8b2018-02-01 10:27:11 -050091 ud.localfile = d.expand('%s_%s_%s.tar.gz' % (cleanedhost, cleanedpath, ud.revision))
Patrick Williamsc0f7c042017-02-23 20:41:17 -060092
93 def _buildp4command(self, ud, d, command, depot_filename=None):
94 """
95 Build a p4 commandline. Valid commands are "changes", "print", and
96 "files". depot_filename is the full path to the file in the depot
97 including the trailing '#rev' value.
98 """
Patrick Williamsc124f4f2015-09-15 14:41:29 -050099 p4opt = ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500100
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600101 if ud.user:
102 p4opt += ' -u "%s"' % (ud.user)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500103
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600104 if ud.pswd:
105 p4opt += ' -P "%s"' % (ud.pswd)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500106
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600107 if ud.host and not ud.usingp4config:
108 p4opt += ' -p %s' % (ud.host)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500109
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600110 if hasattr(ud, 'revision') and ud.revision:
111 pathnrev = '%s@%s' % (ud.path, ud.revision)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500112 else:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600113 pathnrev = '%s' % (ud.path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500114
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600115 if depot_filename:
116 if ud.pathisdir: # Remove leading path to obtain filename
117 filename = depot_filename[len(ud.path)-1:]
118 else:
119 filename = depot_filename[depot_filename.rfind('/'):]
120 filename = filename[:filename.find('#')] # Remove trailing '#rev'
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500121
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600122 if command == 'changes':
123 p4cmd = '%s%s changes -m 1 //%s' % (ud.basecmd, p4opt, pathnrev)
124 elif command == 'print':
125 if depot_filename != None:
126 p4cmd = '%s%s print -o "p4/%s" "%s"' % (ud.basecmd, p4opt, filename, depot_filename)
127 else:
128 raise FetchError('No depot file name provided to p4 %s' % command, ud.url)
129 elif command == 'files':
130 p4cmd = '%s%s files //%s' % (ud.basecmd, p4opt, pathnrev)
131 else:
132 raise FetchError('Invalid p4 command %s' % command, ud.url)
133
134 return p4cmd
135
136 def _p4listfiles(self, ud, d):
137 """
138 Return a list of the file names which are present in the depot using the
139 'p4 files' command, including trailing '#rev' file revision indicator
140 """
141 p4cmd = self._buildp4command(ud, d, 'files')
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500142 bb.fetch2.check_network_access(d, p4cmd, ud.url)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600143 p4fileslist = runfetchcmd(p4cmd, d, True)
144 p4fileslist = [f.rstrip() for f in p4fileslist.splitlines()]
145
146 if not p4fileslist:
147 raise FetchError('Unable to fetch listing of p4 files from %s@%s' % (ud.host, ud.path))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500148
149 count = 0
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600150 filelist = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500151
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600152 for filename in p4fileslist:
153 item = filename.split(' - ')
154 lastaction = item[1].split()
155 logger.debug(1, 'File: %s Last Action: %s' % (item[0], lastaction[0]))
156 if lastaction[0] == 'delete':
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500157 continue
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600158 filelist.append(item[0])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500159
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600160 return filelist
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500161
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600162 def download(self, ud, d):
163 """ Get the list of files, fetch each one """
164 filelist = self._p4listfiles(ud, d)
165 if not filelist:
166 raise FetchError('No files found in depot %s@%s' % (ud.host, ud.path))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500167
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600168 bb.utils.remove(ud.pkgdir, True)
169 bb.utils.mkdirhier(ud.pkgdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500170
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600171 for afile in filelist:
172 p4fetchcmd = self._buildp4command(ud, d, 'print', afile)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500173 bb.fetch2.check_network_access(d, p4fetchcmd, ud.url)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600174 runfetchcmd(p4fetchcmd, d, workdir=ud.pkgdir)
175
176 runfetchcmd('tar -czf %s p4' % (ud.localpath), d, cleanup=[ud.localpath], workdir=ud.pkgdir)
177
178 def clean(self, ud, d):
179 """ Cleanup p4 specific files and dirs"""
180 bb.utils.remove(ud.localpath)
181 bb.utils.remove(ud.pkgdir, True)
182
183 def supports_srcrev(self):
184 return True
185
186 def _revision_key(self, ud, d, name):
187 """ Return a unique key for the url """
188 return 'p4:%s' % ud.pkgdir
189
190 def _latest_revision(self, ud, d, name):
191 """ Return the latest upstream scm revision number """
192 p4cmd = self._buildp4command(ud, d, "changes")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500193 bb.fetch2.check_network_access(d, p4cmd, ud.url)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600194 tip = runfetchcmd(p4cmd, d, True)
195
196 if not tip:
197 raise FetchError('Could not determine the latest perforce changelist')
198
199 tipcset = tip.split(' ')[1]
200 logger.debug(1, 'p4 tip found to be changelist %s' % tipcset)
201 return tipcset
202
203 def sortable_revision(self, ud, d, name):
204 """ Return a sortable revision number """
205 return False, self._build_revision(ud, d)
206
207 def _build_revision(self, ud, d):
208 return ud.revision
209