contrib: remove git-p4import
The git p4import documentation has suggested git p4 as a better alternative for more than 6 years. (According to the mailing list discussion when it was moved to contrib/, git-p4import has serious bugs --- e.g., its incremental mode just doesn't work.) Since then, git p4 has been actively developed and was promoted to a standard git command alongside git svn. Searches on google.com/trends and stackoverflow suggest that no one is looking for git-p4import any more. Remove it. Noticed while considering marking the contrib/p4import/git-p4import.py script executable as part of a wider sweep. Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Acked-by: Pete Wyckoff <pw@padd.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jonathan Nieder committed
Nov 25, 2013 at 12:58 UTC
30a3318ac06c639f0ccb25b3abf627b3120c4dc9
3 files changed
-533
contrib/p4import/README
deleted
-1
@@ -1 +0,0 @@
1
-Please see contrib/fast-import/git-p4 for a better Perforce importer.
contrib/p4import/git-p4import.py
deleted
-365
@@ -1,365 +0,0 @@
1
-#!/usr/bin/env python
2
-#
3
-# This tool is copyright (c) 2006, Sean Estabrooks.
4
-# It is released under the Gnu Public License, version 2.
5
-#
6
-# Import Perforce branches into Git repositories.
7
-# Checking out the files is done by calling the standard p4
8
-# client which you must have properly configured yourself
9
-#
10
-
11
-import marshal
12
-import os
13
-import sys
14
-import time
15
-import getopt
16
-
17
-if sys.hexversion < 0x02020000:
18
- # The behavior of the marshal module changed significantly in 2.2
19
- sys.stderr.write("git-p4import.py: requires Python 2.2 or later.\n")
20
- sys.exit(1)
21
-
22
-from signal import signal, \
23
- SIGPIPE, SIGINT, SIG_DFL, \
24
- default_int_handler
25
-
26
-signal(SIGPIPE, SIG_DFL)
27
-s = signal(SIGINT, SIG_DFL)
28
-if s != default_int_handler:
29
- signal(SIGINT, s)
30
-
31
-def die(msg, *args):
32
- for a in args:
33
- msg = "%s %s" % (msg, a)
34
- print "git-p4import fatal error:", msg
35
- sys.exit(1)
36
-
37
-def usage():
38
- print "USAGE: git-p4import [-q|-v] [--authors=<file>] [-t <timezone>] [//p4repo/path <branch>]"
39
- sys.exit(1)
40
-
41
-verbosity = 1
42
-logfile = "/dev/null"
43
-ignore_warnings = False
44
-stitch = 0
45
-tagall = True
46
-
47
-def report(level, msg, *args):
48
- global verbosity
49
- global logfile
50
- for a in args:
51
- msg = "%s %s" % (msg, a)
52
- fd = open(logfile, "a")
53
- fd.writelines(msg)
54
- fd.close()
55
- if level <= verbosity:
56
- print msg
57
-
58
-class p4_command:
59
- def __init__(self, _repopath):
60
- try:
61
- global logfile
62
- self.userlist = {}
63
- if _repopath[-1] == '/':
64
- self.repopath = _repopath[:-1]
65
- else:
66
- self.repopath = _repopath
67
- if self.repopath[-4:] != "/...":
68
- self.repopath= "%s/..." % self.repopath
69
- f=os.popen('p4 -V 2>>%s'%logfile, 'rb')
70
- a = f.readlines()
71
- if f.close():
72
- raise
73
- except:
74
- die("Could not find the \"p4\" command")
75
-
76
- def p4(self, cmd, *args):
77
- global logfile
78
- cmd = "%s %s" % (cmd, ' '.join(args))
79
- report(2, "P4:", cmd)
80
- f=os.popen('p4 -G %s 2>>%s' % (cmd,logfile), 'rb')
81
- list = []
82
- while 1:
83
- try:
84
- list.append(marshal.load(f))
85
- except EOFError:
86
- break
87
- self.ret = f.close()
88
- return list
89
-
90
- def sync(self, id, force=False, trick=False, test=False):
91
- if force:
92
- ret = self.p4("sync -f %s@%s"%(self.repopath, id))[0]
93
- elif trick:
94
- ret = self.p4("sync -k %s@%s"%(self.repopath, id))[0]
95
- elif test:
96
- ret = self.p4("sync -n %s@%s"%(self.repopath, id))[0]
97
- else:
98
- ret = self.p4("sync %s@%s"%(self.repopath, id))[0]
99
- if ret['code'] == "error":
100
- data = ret['data'].upper()
101
- if data.find('VIEW') > 0:
102
- die("Perforce reports %s is not in client view"% self.repopath)
103
- elif data.find('UP-TO-DATE') < 0:
104
- die("Could not sync files from perforce", self.repopath)
105
-
106
- def changes(self, since=0):
107
- try:
108
- list = []
109
- for rec in self.p4("changes %s@%s,#head" % (self.repopath, since+1)):
110
- list.append(rec['change'])
111
- list.reverse()
112
- return list
113
- except:
114
- return []
115
-
116
- def authors(self, filename):
117
- f=open(filename)
118
- for l in f.readlines():
119
- self.userlist[l[:l.find('=')].rstrip()] = \
120
- (l[l.find('=')+1:l.find('<')].rstrip(),l[l.find('<')+1:l.find('>')])
121
- f.close()
122
- for f,e in self.userlist.items():
123
- report(2, f, ":", e[0], " <", e[1], ">")
124
-
125
- def _get_user(self, id):
126
- if not self.userlist.has_key(id):
127
- try:
128
- user = self.p4("users", id)[0]
129
- self.userlist[id] = (user['FullName'], user['Email'])
130
- except:
131
- self.userlist[id] = (id, "")
132
- return self.userlist[id]
133
-
134
- def _format_date(self, ticks):
135
- symbol='+'
136
- name = time.tzname[0]
137
- offset = time.timezone
138
- if ticks[8]:
139
- name = time.tzname[1]
140
- offset = time.altzone
141
- if offset < 0:
142
- offset *= -1
143
- symbol = '-'
144
- localo = "%s%02d%02d %s" % (symbol, offset / 3600, offset % 3600, name)
145
- tickso = time.strftime("%a %b %d %H:%M:%S %Y", ticks)
146
- return "%s %s" % (tickso, localo)
147
-
148
- def where(self):
149
- try:
150
- return self.p4("where %s" % self.repopath)[-1]['path']
151
- except:
152
- return ""
153
-
154
- def describe(self, num):
155
- desc = self.p4("describe -s", num)[0]
156
- self.msg = desc['desc']
157
- self.author, self.email = self._get_user(desc['user'])
158
- self.date = self._format_date(time.localtime(long(desc['time'])))
159
- return self
160
-
161
-class git_command:
162
- def __init__(self):
163
- try:
164
- self.version = self.git("--version")[0][12:].rstrip()
165
- except:
166
- die("Could not find the \"git\" command")
167
- try:
168
- self.gitdir = self.get_single("rev-parse --git-dir")
169
- report(2, "gdir:", self.gitdir)
170
- except:
171
- die("Not a git repository... did you forget to \"git init\" ?")
172
- try:
173
- self.cdup = self.get_single("rev-parse --show-cdup")
174
- if self.cdup != "":
175
- os.chdir(self.cdup)
176
- self.topdir = os.getcwd()
177
- report(2, "topdir:", self.topdir)
178
- except:
179
- die("Could not find top git directory")
180
-
181
- def git(self, cmd):
182
- global logfile
183
- report(2, "GIT:", cmd)
184
- f=os.popen('git %s 2>>%s' % (cmd,logfile), 'rb')
185
- r=f.readlines()
186
- self.ret = f.close()
187
- return r
188
-
189
- def get_single(self, cmd):
190
- return self.git(cmd)[0].rstrip()
191
-
192
- def current_branch(self):
193
- try:
194
- testit = self.git("rev-parse --verify HEAD")[0]
195
- return self.git("symbolic-ref HEAD")[0][11:].rstrip()
196
- except:
197
- return None
198
-
199
- def get_config(self, variable):
200
- try:
201
- return self.git("config --get %s" % variable)[0].rstrip()
202
- except:
203
- return None
204
-
205
- def set_config(self, variable, value):
206
- try:
207
- self.git("config %s %s"%(variable, value) )
208
- except:
209
- die("Could not set %s to " % variable, value)
210
-
211
- def make_tag(self, name, head):
212
- self.git("tag -f %s %s"%(name,head))
213
-
214
- def top_change(self, branch):
215
- try:
216
- a=self.get_single("name-rev --tags refs/heads/%s" % branch)
217
- loc = a.find(' tags/') + 6
218
- if a[loc:loc+3] != "p4/":
219
- raise
220
- return int(a[loc+3:][:-2])
221
- except:
222
- return 0
223
-
224
- def update_index(self):
225
- self.git("ls-files -m -d -o -z | git update-index --add --remove -z --stdin")
226
-
227
- def checkout(self, branch):
228
- self.git("checkout %s" % branch)
229
-
230
- def repoint_head(self, branch):
231
- self.git("symbolic-ref HEAD refs/heads/%s" % branch)
232
-
233
- def remove_files(self):
234
- self.git("ls-files | xargs rm")
235
-
236
- def clean_directories(self):
237
- self.git("clean -d")
238
-
239
- def fresh_branch(self, branch):
240
- report(1, "Creating new branch", branch)
241
- self.git("ls-files | xargs rm")
242
- os.remove(".git/index")
243
- self.repoint_head(branch)
244
- self.git("clean -d")
245
-
246
- def basedir(self):
247
- return self.topdir
248
-
249
- def commit(self, author, email, date, msg, id):
250
- self.update_index()
251
- fd=open(".msg", "w")
252
- fd.writelines(msg)
253
- fd.close()
254
- try:
255
- current = self.get_single("rev-parse --verify HEAD")
256
- head = "-p HEAD"
257
- except:
258
- current = ""
259
- head = ""
260
- tree = self.get_single("write-tree")
261
- for r,l in [('DATE',date),('NAME',author),('EMAIL',email)]:
262
- os.environ['GIT_AUTHOR_%s'%r] = l
263
- os.environ['GIT_COMMITTER_%s'%r] = l
264
- commit = self.get_single("commit-tree %s %s < .msg" % (tree,head))
265
- os.remove(".msg")
266
- self.make_tag("p4/%s"%id, commit)
267
- self.git("update-ref HEAD %s %s" % (commit, current) )
268
-
269
-try:
270
- opts, args = getopt.getopt(sys.argv[1:], "qhvt:",
271
- ["authors=","help","stitch=","timezone=","log=","ignore","notags"])
272
-except getopt.GetoptError:
273
- usage()
274
-
275
-for o, a in opts:
276
- if o == "-q":
277
- verbosity = 0
278
- if o == "-v":
279
- verbosity += 1
280
- if o in ("--log"):
281
- logfile = a
282
- if o in ("--notags"):
283
- tagall = False
284
- if o in ("-h", "--help"):
285
- usage()
286
- if o in ("--ignore"):
287
- ignore_warnings = True
288
-
289
-git = git_command()
290
-branch=git.current_branch()
291
-
292
-for o, a in opts:
293
- if o in ("-t", "--timezone"):
294
- git.set_config("perforce.timezone", a)
295
- if o in ("--stitch"):
296
- git.set_config("perforce.%s.path" % branch, a)
297
- stitch = 1
298
-
299
-if len(args) == 2:
300
- branch = args[1]
301
- git.checkout(branch)
302
- if branch == git.current_branch():
303
- die("Branch %s already exists!" % branch)
304
- report(1, "Setting perforce to ", args[0])
305
- git.set_config("perforce.%s.path" % branch, args[0])
306
-elif len(args) != 0:
307
- die("You must specify the perforce //depot/path and git branch")
308
-
309
-p4path = git.get_config("perforce.%s.path" % branch)
310
-if p4path == None:
311
- die("Do not know Perforce //depot/path for git branch", branch)
312
-
313
-p4 = p4_command(p4path)
314
-
315
-for o, a in opts:
316
- if o in ("-a", "--authors"):
317
- p4.authors(a)
318
-
319
-localdir = git.basedir()
320
-if p4.where()[:len(localdir)] != localdir:
321
- report(1, "**WARNING** Appears p4 client is misconfigured")
322
- report(1, " for sync from %s to %s" % (p4.repopath, localdir))
323
- if ignore_warnings != True:
324
- die("Reconfigure or use \"--ignore\" on command line")
325
-
326
-if stitch == 0:
327
- top = git.top_change(branch)
328
-else:
329
- top = 0
330
-changes = p4.changes(top)
331
-count = len(changes)
332
-if count == 0:
333
- report(1, "Already up to date...")
334
- sys.exit(0)
335
-
336
-ptz = git.get_config("perforce.timezone")
337
-if ptz:
338
- report(1, "Setting timezone to", ptz)
339
- os.environ['TZ'] = ptz
340
- time.tzset()
341
-
342
-if stitch == 1:
343
- git.remove_files()
344
- git.clean_directories()
345
- p4.sync(changes[0], force=True)
346
-elif top == 0 and branch != git.current_branch():
347
- p4.sync(changes[0], test=True)
348
- report(1, "Creating new initial commit");
349
- git.fresh_branch(branch)
350
- p4.sync(changes[0], force=True)
351
-else:
352
- p4.sync(changes[0], trick=True)
353
-
354
-report(1, "processing %s changes from p4 (%s) to git (%s)" % (count, p4.repopath, branch))
355
-for id in changes:
356
- report(1, "Importing changeset", id)
357
- change = p4.describe(id)
358
- p4.sync(id)
359
- if tagall :
360
- git.commit(change.author, change.email, change.date, change.msg, id)
361
- else:
362
- git.commit(change.author, change.email, change.date, change.msg, "import")
363
- if stitch == 1:
364
- git.clean_directories()
365
- stitch = 0
contrib/p4import/git-p4import.txt
deleted
-167
@@ -1,167 +0,0 @@
1
-git-p4import(1)
2
-===============
3
-
4
-NAME
5
-----
6
-git-p4import - Import a Perforce repository into git
7
-
8
-
9
-SYNOPSIS
10
---------
11
-[verse]
12
-`git-p4import` [-q|-v] [--notags] [--authors <file>] [-t <timezone>]
13
- <//p4repo/path> <branch>
14
-`git-p4import` --stitch <//p4repo/path>
15
-`git-p4import`
16
-
17
-
18
-DESCRIPTION
19
------------
20
-Import a Perforce repository into an existing git repository. When
21
-a <//p4repo/path> and <branch> are specified a new branch with the
22
-given name will be created and the initial import will begin.
23
-
24
-Once the initial import is complete you can do an incremental import
25
-of new commits from the Perforce repository. You do this by checking
26
-out the appropriate git branch and then running `git-p4import` without
27
-any options.
28
-
29
-The standard p4 client is used to communicate with the Perforce
30
-repository; it must be configured correctly in order for `git-p4import`
31
-to operate (see below).
32
-
33
-
34
-OPTIONS
35
--------
36
--q::
37
- Do not display any progress information.
38
-
39
--v::
40
- Give extra progress information.
41
-
42
-\--authors::
43
- Specify an authors file containing a mapping of Perforce user
44
- ids to full names and email addresses (see Notes below).
45
-
46
-\--notags::
47
- Do not create a tag for each imported commit.
48
-
49
-\--stitch::
50
- Import the contents of the given perforce branch into the
51
- currently checked out git branch.
52
-
53
-\--log::
54
- Store debugging information in the specified file.
55
-
56
--t::
57
- Specify that the remote repository is in the specified timezone.
58
- Timezone must be in the format "US/Pacific" or "Europe/London"
59
- etc. You only need to specify this once, it will be saved in
60
- the git config file for the repository.
61
-
62
-<//p4repo/path>::
63
- The Perforce path that will be imported into the specified branch.
64
-
65
-<branch>::
66
- The new branch that will be created to hold the Perforce imports.
67
-
68
-
69
-P4 Client
70
----------
71
-You must make the `p4` client command available in your $PATH and
72
-configure it to communicate with the target Perforce repository.
73
-Typically this means you must set the "$P4PORT" and "$P4CLIENT"
74
-environment variables.
75
-
76
-You must also configure a `p4` client "view" which maps the Perforce
77
-branch into the top level of your git repository, for example:
78
-
79
-------------
80
-Client: myhost
81
-
82
-Root: /home/sean/import
83
-
84
-Options: noallwrite clobber nocompress unlocked modtime rmdir
85
-
86
-View:
87
- //public/jam/... //myhost/jam/...
88
-------------
89
-
90
-With the above `p4` client setup, you could import the "jam"
91
-perforce branch into a branch named "jammy", like so:
92
-
93
-------------
94
-$ mkdir -p /home/sean/import/jam
95
-$ cd /home/sean/import/jam
96
-$ git init
97
-$ git p4import //public/jam jammy
98
-------------
99
-
100
-
101
-Multiple Branches
102
------------------
103
-Note that by creating multiple "views" you can use `git-p4import`
104
-to import additional branches into the same git repository.
105
-However, the `p4` client has a limitation in that it silently
106
-ignores all but the last "view" that maps into the same local
107
-directory. So the following will *not* work:
108
-
109
-------------
110
-View:
111
- //public/jam/... //myhost/jam/...
112
- //public/other/... //myhost/jam/...
113
- //public/guest/... //myhost/jam/...
114
-------------
115
-
116
-If you want more than one Perforce branch to be imported into the
117
-same directory you must employ a workaround. A simple option is
118
-to adjust your `p4` client before each import to only include a
119
-single view.
120
-
121
-Another option is to create multiple symlinks locally which all
122
-point to the same directory in your git repository and then use
123
-one per "view" instead of listing the actual directory.
124
-
125
-
126
-Tags
127
-----
128
-A git tag of the form p4/xx is created for every change imported from
129
-the Perforce repository where xx is the Perforce changeset number.
130
-Therefore after the import you can use git to access any commit by its
131
-Perforce number, e.g. git show p4/327.
132
-
133
-The tag associated with the HEAD commit is also how `git-p4import`
134
-determines if there are new changes to incrementally import from the
135
-Perforce repository.
136
-
137
-If you import from a repository with many thousands of changes
138
-you will have an equal number of p4/xxxx git tags. Git tags can
139
-be expensive in terms of disk space and repository operations.
140
-If you don't need to perform further incremental imports, you
141
-may delete the tags.
142
-
143
-
144
-Notes
145
------
146
-You can interrupt the import (e.g. ctrl-c) at any time and restart it
147
-without worry.
148
-
149
-Author information is automatically determined by querying the
150
-Perforce "users" table using the id associated with each change.
151
-However, if you want to manually supply these mappings you can do
152
-so with the "--authors" option. It accepts a file containing a list
153
-of mappings with each line containing one mapping in the format:
154
-
155
-------------
156
- perforce_id = Full Name <email@address.com>
157
-------------
158
-
159
-
160
-Author
161
-------
162
-Written by Sean Estabrooks <seanlkml@sympatico.ca>
163
-
164
-
165
-GIT
166
----
167
-Part of the gitlink:git[7] suite