#!/usr/bin/env ruby # git.rb - a P4 shim that pretends to be Git so that it can work with Xcode # entirely experimental: here be dragons require 'fileutils' begin f = File.open('/Users/matt/fauxgit_log.txt', 'a') f.puts ARGV.join(' ') f.puts "Total args: #{ARGV.size()}" p4 = '/usr/local/bin/p4' # require a P4 URI because it's my tool # URIs are of the form [username@]p4://<hostname[:port]/<depot path> case ARGV[0] when 'clone' matches = /p4:\/\/(.+?)@(.+?)\/(.*)|p4:\/\/(.+?)\/(.*)/.match(ARGV[4]) user = matches.captures[0] port = matches.captures[1] || matches.captures[3] path = matches.captures[2] || matches.captures[4] # let's be civilized and not require a port if port !~ /:\d*/ port = port + ":1666" end cmd = "#{p4} -d #{ARGV[5]}" cmd += " -u #{user}" if user # running the clone and creating a fake git repo to appease Xcode f.puts "#{cmd} clone -p #{port} -f //#{path}/..." `#{cmd} clone -p #{port} -f //#{path}/...` FileUtils.mkdir_p "#{ARGV[5]}/.git/info" FileUtils.mkdir_p "#{ARGV[5]}/.git/refs" FileUtils.mkdir_p "#{ARGV[5]}/.git/objects" FileUtils.mkdir_p "#{ARGV[5]}/.git/hooks" FileUtils.touch "#{ARGV[5]}/.git/HEAD" FileUtils.touch "#{ARGV[5]}/.git/config" FileUtils.touch "#{ARGV[5]}/.git/description" # totally lying here, but it seems to make XCode happy? # will experiment sometime with removing this now that I # do a better job of creating the directories it wants puts "Cloning into '#{ARGV[4]}'..." puts "remote: Counting objects: 596, done." puts "remote: Compressing objects: 100% (309/309), done." puts "remote: Total 596 (delta 275), reused 596 (delta 275)" puts "Receiving objects: 100% (596/596), 107.22 KiB | 0 bytes/s, done." puts "Resolving deltas: 100% (275/275), done." puts "Checking connectivity... done." when 'init' f.puts "#{p4} init" `#{p4} init` FileUtils.mkdir_p ".git/info" FileUtils.mkdir_p ".git/refs" FileUtils.mkdir_p ".git/objects" FileUtils.mkdir_p ".git/hooks" FileUtils.touch ".git/HEAD" FileUtils.touch ".git/config" FileUtils.touch ".git/description" when 'add' f.puts "#{p4} rec" `#{p4} rec ...` when 'status' f.puts "#{p4} -ztag -F '%change% %action% %localFile%' status" results = `#{p4} -ztag -F '%change% %action% %localFile%' status` results.each_line do |r| if r.start_with?(' add ') puts "?? #{r.split(' ')[1]}" elsif r.start_with?('default add ') puts "A #{r.split(' ')[2]}" elsif r.start_with?(' edit ') puts " M #{r.split(' ')[1]}" elsif r.start_with?('default edit ') puts "M #{r.split(' ')[2]}" elsif r.start_with?(' delete ') puts " D #{r.split(' ')[1]}" elsif r.start_with?('default delete ') puts "D #{r.split(' ')[2]}" end end when 'branch' if ARGV.size() == 1 results = `#{p4} switch -l` results.each_line do |r| if r.end_with?("*\n") puts "* #{r.split(' ')[0]}" else puts " #{r}" end end elsif ARGV.size() == 3 results = `#{p4} switch -cr -P #{ARGV[2]} #{ARGV[1]}` end when 'mv' f.puts "#{p4} edit #{ARGV[1]}" f.puts "#{p4} move #{ARGV[1]} #{ARGV[2]}" `#{p4} edit #{ARGV[1]}` `#{p4} move #{ARGV[1]} #{ARGV[2]}` when 'rm' if ARGV[1] == '-f' && ARGV[2] == '-r' && ARGV[3] == '--' ARGV[4..-1].each do |f| f.puts "#{p4} delete #{f}" f.puts "#{p4} delete #{f}/..." `#{p4} delete #{f}` `#{p4} delete #{f}/...` end end when 'commit' `#{p4} rec` # Git forces the file to commit by specifying it, we don't have that `#{p4} submit -d #{ARGV[2]}` when 'checkout' `#{p4} switch #{ARGV[1]}` when 'blame' puts 'p4 annotate' when 'archive' STDOUT.write `find . -name #{ARGV[2]} | xargs /usr/bin/tar c` when 'log' `p4 changes -m1` when 'config' && ARGV[1] == '--get' if ARGV[2] == 'branch.default.remote' puts 'default' elsif ARGV[2] == 'branch.default.merge' puts 'refs/heads/default' elsif ARGV[2] == 'remote.origin.url' puts 'matt_attaway@perforce.com/stuff' end when 'remote' puts "origin\x09http://xxxxx (fetch)" puts "origin\x09http://xxxxx (push)" when 'ls-remote' puts "3828d854bb849581255a20cbbc4e0e639fba2eb7\trefs/heads/master" end f.puts "" f.close() end
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#7 | 11819 | Matt Attaway |
Hacky version of submit This will commit, but poorly. Currently commits all changed files. |
||
#6 | 11818 | Matt Attaway |
Add support for creating new branches from XCode, as well as switching branches This change properly implements 'git branch' and 'git branch <target> <source>', translating them to the proper p4 commands. |
||
#5 | 11715 | Matt Attaway |
Enable cloning from a Perforce server from Xcode By putting in a URI of the form: p4://[username@]<hostname>[:port]/<depot path for a directory with no '...'> for example: p4://matt_attaway@workshop.perforce.com/guest/matt_attaway/fauxgit This change cleans up the URI syntax and fakes one branch result from 'ls-remote'. It also creates the trappings of a fake Git repo so that Xcode will enable its source control menu items. Status shows up correctly so far and adding new files seems to work. I suspect that deleting and renaming files works as well, but I haven't test it. |
||
#4 | 11706 | Matt Attaway | Make both scripts executable | ||
#3 | 11705 | Matt Attaway |
Add support for git branch and git add Branch is pretty straight forward, but add may need some work. Based on what I've seen so far from watching Xcode 'git add .' is all I need to support. |
||
#2 | 11625 | Matt Attaway | Fix silly double p4port bug when port is specified in URI | ||
#1 | 11624 | Matt Attaway |
Initial drop of my work on p4 in git clothing Inspired by the work of hsivank: https://bitbucket.org/hsivank/xcode4-with-mercurial/overview I've decided to make my own drop in Git replacement built on top of 15.1 p4. Currently it can handle cloning, init, status, mv, rm, and add. At least I think it can; it hasn't been tested with Xcode yet... Snooper.rb is a script to intercept Git commands called from Xcode so that I can figure out what the output needs to look like. Clone requires a p4 URI of the form: [username@]p4://<hostname>[:port]/<depot path> |