Fetcher SRCREV handling updates, improvements and fixes from Poky, typo fix for bin...
[bitbake.git] / lib / bb / fetch / perforce.py
1 # ex:ts=4:sw=4:sts=4:et
2 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3 """
4 BitBake 'Fetch' implementations
5
6 Classes for obtaining upstream sources for the
7 BitBake build tools.
8
9 """
10
11 # Copyright (C) 2003, 2004  Chris Larson
12 #
13 # This program is free software; you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License version 2 as
15 # published by the Free Software Foundation.
16 #
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 # GNU General Public License for more details.
21 #
22 # You should have received a copy of the GNU General Public License along
23 # with this program; if not, write to the Free Software Foundation, Inc.,
24 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #
26 # Based on functions from the base bb module, Copyright 2003 Holger Schurig
27
28 import os, re
29 import bb
30 from   bb import data
31 from   bb.fetch import Fetch
32 from   bb.fetch import FetchError
33 from   bb.fetch import MissingParameterError
34
35 class Perforce(Fetch):
36     def supports(self, url, ud, d):
37         return ud.type in ['p4']
38
39     def doparse(url,d):
40         parm = {}
41         path = url.split("://")[1]
42         delim = path.find("@");
43         if delim != -1:
44             (user,pswd,host,port) = path.split('@')[0].split(":")
45             path = path.split('@')[1]
46         else:
47             (host,port) = data.getVar('P4PORT', d).split(':')
48             user = ""
49             pswd = ""
50
51         if path.find(";") != -1:
52             keys=[]
53             values=[]
54             plist = path.split(';')
55             for item in plist:
56                 if item.count('='):
57                     (key,value) = item.split('=')
58                     keys.append(key)
59                     values.append(value)
60
61             parm = dict(zip(keys,values))
62         path = "//" + path.split(';')[0]
63         host += ":%s" % (port)
64         parm["cset"] = Perforce.getcset(d, path, host, user, pswd, parm)
65
66         return host,path,user,pswd,parm
67     doparse = staticmethod(doparse)
68
69     def getcset(d, depot,host,user,pswd,parm):
70         if "cset" in parm:
71             return parm["cset"];
72         if user:
73             data.setVar('P4USER', user, d)
74         if pswd:
75             data.setVar('P4PASSWD', pswd, d)
76         if host:
77             data.setVar('P4PORT', host, d)
78
79         p4date = data.getVar("P4DATE", d, 1)
80         if "revision" in parm:
81             depot += "#%s" % (parm["revision"])
82         elif "label" in parm:
83             depot += "@%s" % (parm["label"])
84         elif p4date:
85             depot += "@%s" % (p4date)
86
87         p4cmd = data.getVar('FETCHCOMMAND_p4', d, 1)
88         bb.msg.debug(1, bb.msg.domain.Fetcher, "Running %s changes -m 1 %s" % (p4cmd, depot))
89         p4file = os.popen("%s changes -m 1 %s" % (p4cmd,depot))
90         cset = p4file.readline().strip()
91         bb.msg.debug(1, bb.msg.domain.Fetcher, "READ %s" % (cset))
92         if not cset:
93             return -1
94
95         return cset.split(' ')[1]
96     getcset = staticmethod(getcset)
97
98     def localpath(self, url, ud, d):        
99
100         (host,path,user,pswd,parm) = Perforce.doparse(url,d)
101
102         # If a label is specified, we use that as our filename
103
104         if "label" in parm:
105             ud.localfile = "%s.tar.gz" % (parm["label"])
106             return os.path.join(data.getVar("DL_DIR", d, 1), ud.localfile)
107
108         base = path
109         which = path.find('/...')
110         if which != -1:
111             base = path[:which]
112
113         if base[0] == "/":
114             base = base[1:]
115
116         cset = Perforce.getcset(d, path, host, user, pswd, parm)
117
118         ud.localfile = data.expand('%s+%s+%s.tar.gz' % (host,base.replace('/', '.'), cset), d)
119
120         return os.path.join(data.getVar("DL_DIR", d, 1), ud.localfile)
121
122     def go(self, loc, ud, d):
123         """
124         Fetch urls
125         """
126
127         # try to use the tarball stash
128         if Fetch.try_mirror(d, ud.localfile):
129             bb.msg.debug(1, bb.msg.domain.Fetcher, "%s already exists or was mirrored, skipping perforce checkout." % ud.localpath)
130             return
131
132         (host,depot,user,pswd,parm) = Perforce.doparse(loc, d)
133
134         if depot.find('/...') != -1:
135             path = depot[:depot.find('/...')]
136         else:
137             path = depot
138
139         if "module" in parm:
140             module = parm["module"]
141         else:
142             module = os.path.basename(path)
143
144         localdata = data.createCopy(d)
145         data.setVar('OVERRIDES', "p4:%s" % data.getVar('OVERRIDES', localdata), localdata)
146         data.update_data(localdata)
147
148         # Get the p4 command
149         if user:
150             data.setVar('P4USER', user, localdata)
151
152         if pswd:
153             data.setVar('P4PASSWD', pswd, localdata)
154
155         if host:
156             data.setVar('P4PORT', host, localdata)
157
158         p4cmd = data.getVar('FETCHCOMMAND', localdata, 1)
159
160         # create temp directory
161         bb.msg.debug(2, bb.msg.domain.Fetcher, "Fetch: creating temporary directory")
162         bb.mkdirhier(data.expand('${WORKDIR}', localdata))
163         data.setVar('TMPBASE', data.expand('${WORKDIR}/oep4.XXXXXX', localdata), localdata)
164         tmppipe = os.popen(data.getVar('MKTEMPDIRCMD', localdata, 1) or "false")
165         tmpfile = tmppipe.readline().strip()
166         if not tmpfile:
167             bb.error("Fetch: unable to create temporary directory.. make sure 'mktemp' is in the PATH.")
168             raise FetchError(module)
169
170         if "label" in parm:
171             depot = "%s@%s" % (depot,parm["label"])
172         else:
173             cset = Perforce.getcset(d, depot, host, user, pswd, parm)
174             depot = "%s@%s" % (depot,cset)
175
176         os.chdir(tmpfile)
177         bb.msg.note(1, bb.msg.domain.Fetcher, "Fetch " + loc)
178         bb.msg.note(1, bb.msg.domain.Fetcher, "%s files %s" % (p4cmd, depot))
179         p4file = os.popen("%s files %s" % (p4cmd, depot))
180
181         if not p4file:
182             bb.error("Fetch: unable to get the P4 files from %s" % (depot))
183             raise FetchError(module)
184
185         count = 0
186
187         for file in p4file: 
188             list = file.split()
189
190             if list[2] == "delete":
191                 continue
192
193             dest = list[0][len(path)+1:]
194             where = dest.find("#")
195
196             os.system("%s print -o %s/%s %s" % (p4cmd, module,dest[:where],list[0]))
197             count = count + 1
198             
199         if count == 0:
200             bb.error("Fetch:  No files gathered from the P4 fetch")
201             raise FetchError(module)
202
203         myret = os.system("tar -czf %s %s" % (ud.localpath, module))
204         if myret != 0:
205             try:
206                 os.unlink(ud.localpath)
207             except OSError:
208                 pass
209             raise FetchError(module)
210         # cleanup
211         os.system('rm -rf %s' % tmpfile)
212
213