Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100755 604 lines (516 sloc) 20.238 kb
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
1 #!/usr/bin/env ruby
0ef52d43 »
2011-01-24 Explicitly set script coding to utf-8, to avoid issues with embedded …
2 # -*- coding: utf-8 -*-
648f1b69 » Steve
2007-10-11 Add author header and a note about running in a empty directory
3 ##
4 ## Author: Steve Purcell, http://www.sanityinc.com/
ab88fa61 »
2010-08-25 Documentation updates
5 ##
6 ## Further info:
7 ## http://www.sanityinc.com/articles/converting-darcs-repositories-to-git
8 ##
9 ## Obtain the latest version of this software here:
10 ##
bf6f5825 »
2011-07-29 Add note about where to file issues
11 ## https://github.com/purcell/darcs-to-git
ab88fa61 »
2010-08-25 Documentation updates
12 ## http://git.sanityinc.com/
13 ##
bf6f5825 »
2011-07-29 Add note about where to file issues
14 ## Please submit bug reports and patches via Github if possible:
15 ##
16 ## https://github.com/purcell/darcs-to-git/issues
17 ##
18 ## or by email to the author if necessary.
ab88fa61 »
2010-08-25 Documentation updates
19 ##
648f1b69 » Steve
2007-10-11 Add author header and a note about running in a empty directory
20 ##
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
21
ea749209 » nominolo
2008-05-09 Update TODOs
22 # XXX: make backwards compatible
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
23 # TODO: import parallel darcs repos as git branches, identifying branch points
ea749209 » nominolo
2008-05-09 Update TODOs
24 # TODO: use default repo if none was supplied
ae775b5a »
2008-05-12 Return to storing darcs-hash in commit comments, but provide an optio…
25 # TODO: handle *-darcs-backupN files?
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
26
27 require 'ostruct'
28 require 'rexml/document'
24157c1c » nominolo
2008-05-07 Add argument handling and add argument for default email address
29 require 'optparse'
76cbfc22 » nominolo
2008-05-09 Allow listing of authors
30 require 'yaml'
518b74a4 » jmah
2009-08-29 Add borings to the global darcs boring file
31 require 'pathname'
e6ddd9e1 » kerneis
2010-03-09 Strip invalid byte sequences from input
32 require 'iconv'
10c9e8e4 »
2010-08-27 Fix capitalisation of library name
33 require 'shellwords'
19b2143a »
2011-03-03 Create .git/info/exclude ourselves if "git init" doesn't, e.g. becaus…
34 require 'fileutils'
e3692279 »
2011-03-03 Support mirroring remote darcs repos directly, without having to crea…
35 require 'open-uri'
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
36
c547c011 » nominolo
2008-05-07 Proper handling of timezones
37 # Explicitly setting a time zone would cause darcs to only output in
38 # that timezone hence we couldn't get the actual patch TZ
39 # ENV['TZ'] = 'GMT0'
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
40
c213d243 » nominolo
2008-05-07 Move darcs hashes out of commit messages. By default they now go into
41 GIT_PATCHES = ".git/darcs_patches"
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
42 DEFAULT_AUTHOR_MAP_FILE = ".git/darcs_author_substitutions"
43
44 # -------------------------------------------------------------------------------
45 # Usage info and argument parsing
46 # -------------------------------------------------------------------------------
b0d32921 »
2008-02-17 Add more details usage info, as requested by Samuel Bronson
47
51249de4 » thomie
2010-08-15 Add non-nil default values for name and email.
48 OPTIONS = { :default_author => 'none',
49 :default_email => 'none',
6e40cd31 » nominolo
2008-05-09 Add some more options
50 :list_authors => false,
51 :author_map => nil,
0b6c86f6 »
2011-03-04 Add a --verbose option, and don't show executed commands without it
52 :verbose => false,
53 :quiet => false,
110ec156 » thomie
2010-08-15 Add no-check option. Runs 2x faster on testrepo.
54 :do_checks => true,
ae775b5a »
2008-05-12 Return to storing darcs-hash in commit comments, but provide an optio…
55 :clean_commit_messages => false,
f5bf94d8 »
2008-05-12 Clean up logic linking --patches option and running of post-flight co…
56 :num_patches => nil }
24157c1c » nominolo
2008-05-07 Add argument handling and add argument for default email address
57 opts = OptionParser.new do |opts|
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
58 opts.banner = <<-end_usage
59 Creates git repositories from darcs repositories
24157c1c » nominolo
2008-05-07 Add argument handling and add argument for default email address
60
e3692279 »
2011-03-03 Support mirroring remote darcs repos directly, without having to crea…
61 usage: darcs-to-git DARCSREPO [options]
b0d32921 »
2008-02-17 Add more details usage info, as requested by Samuel Bronson
62
63
64 1. Create an *empty* directory that will become the new git repository
65 2. From inside that directory, run this program, passing the location
e3692279 »
2011-03-03 Support mirroring remote darcs repos directly, without having to crea…
66 of the source darcs repo as a parameter
b0d32921 »
2008-02-17 Add more details usage info, as requested by Samuel Bronson
67
68 The program will git-init the empty directory, and migrate all patches
69 in the source darcs repo into commits in that repository.
70
71 Thereafter, incremental patch conversion from the same source repo is
72 possible by repeating step 2.
24157c1c » nominolo
2008-05-07 Add argument handling and add argument for default email address
73
e3692279 »
2011-03-03 Support mirroring remote darcs repos directly, without having to crea…
74 If DARCSREPO is local, its contents will be compared with those of the
75 git repo after conversion finishes, as a sanity check for the
76 conversion process.
77
2f112862 »
2011-02-03 When duplicate tags exist, allow later taggings to override previous …
78 NOTE: In case of duplicate tags, the latest will take precedence.
79 If you really need to, you can manually identify the patch and use
53218c82 » nominolo
2008-05-07 Document that only the first tag will be applied.
80 \"git tag -f <tagname> <sha1-of-commit-before-tagging>\".
81
82 OPTIONS
83
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
84 end_usage
e6dbc648 » thomie
2010-08-13 Add default_author option.
85 opts.on('--default-author NAME',
86 "Set the author name used when darcs patch has no explicit author") do |m|
87 OPTIONS[:default_author] = m
88 end
1311774a » nominolo
2008-05-09 Remove short options
89 opts.on('--default-email ADDRESS',
24157c1c » nominolo
2008-05-07 Add argument handling and add argument for default email address
90 "Set the email address used when no explicit address is given") do |m|
6e40cd31 » nominolo
2008-05-09 Add some more options
91 OPTIONS[:default_email] = m
92 end
1311774a » nominolo
2008-05-09 Remove short options
93 opts.on('--list-authors',
6e40cd31 » nominolo
2008-05-09 Add some more options
94 "List all unique authors in source repo and quit.") do |m|
95 OPTIONS[:list_authors] = m
96 end
1311774a » nominolo
2008-05-09 Remove short options
97 opts.on('--author-map FILE',
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
98 "Supply a YAML file that maps committer names to canonical author names") do |f|
6e40cd31 » nominolo
2008-05-09 Add some more options
99 OPTIONS[:author_map] = f
100 end
101 opts.on('--patches [N]', OptionParser::DecimalInteger,
102 "Only pull N patches.") do |n|
f5bf94d8 »
2008-05-12 Clean up logic linking --patches option and running of post-flight co…
103 abort opts.to_s unless n >= 0
6e40cd31 » nominolo
2008-05-09 Add some more options
104 OPTIONS[:num_patches] = n
24157c1c » nominolo
2008-05-07 Add argument handling and add argument for default email address
105 end
0b6c86f6 »
2011-03-04 Add a --verbose option, and don't show executed commands without it
106 opts.on('--verbose',
107 "Show executed commands and other internal information") do |n|
108 OPTIONS[:verbose] = true
109 end
8c354797 » thomie
2010-08-15 Add --no-verbose options and show progress.
110 opts.on('--no-verbose',
111 "Don't show status update after every imported patch (bit faster) ") do |n|
0b6c86f6 »
2011-03-04 Add a --verbose option, and don't show executed commands without it
112 OPTIONS[:quiet] = true
8c354797 » thomie
2010-08-15 Add --no-verbose options and show progress.
113 end
110ec156 » thomie
2010-08-15 Add no-check option. Runs 2x faster on testrepo.
114 opts.on('--no-checks',
115 "Don't check repository consistency after every imported patch, only at start and finish of pull (faster) ") do |n|
116 OPTIONS[:do_checks] = false
117 end
ae775b5a »
2008-05-12 Return to storing darcs-hash in commit comments, but provide an optio…
118 opts.on('--clean-commit-messages',
119 "Don't note darcs hashes in git commit messages (not recommended)") do |n|
120 OPTIONS[:clean_commit_messages] = true
121 end
4271fa35 » Simon Huerlimann
2009-01-02 add --version option => make help2man happy
122 opts.on('--version', "Output version information and exit") do
123 puts <<-EOF
e86c9c03 »
2011-07-19 More aggressively clear out darcs backup files when importing conflic…
124 darcs-to-git 0.2
4271fa35 » Simon Huerlimann
2009-01-02 add --version option => make help2man happy
125
e86c9c03 »
2011-07-19 More aggressively clear out darcs backup files when importing conflic…
126 Copyright (c) 2009-#{Time.now.year} Steve Purcell, http://www.sanityinc.com/
4271fa35 » Simon Huerlimann
2009-01-02 add --version option => make help2man happy
127
128 License MIT: <http://www.opensource.org/licenses/mit-license.php>
129 This is free software: you are free to change and redistribute it.
130 There is NO WARRANTY, to the extent permitted by law.
131 EOF
132 exit
133 end
134
2690e4ba »
2008-05-12 Add a --help option
135 opts.on('-h', '--help', "Show this message") do
3b115166 » Simon Huerlimann
2009-01-02 exit with 0, not 1 if explicitly called with --help or -h
136 puts opts.to_s
137 exit
2690e4ba »
2008-05-12 Add a --help option
138 end
24157c1c » nominolo
2008-05-07 Add argument handling and add argument for default email address
139 end
140 opts.parse!
141
142 SRCREPO = ARGV[0]
ffd9c8df »
2008-05-12 Tidy up consistency check code, and fix some unidiomatic constructions
143 if SRCREPO.nil?
2690e4ba »
2008-05-12 Add a --help option
144 abort opts.to_s
de433de4 »
2008-02-17 Add -h/--help switches (requested by Brenda Wallace)
145 end
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
146
bd442b41 »
2008-05-10 Move DarcsPatch#decode_darcs_escape to String#darcs_unescape
147
148 # -------------------------------------------------------------------------------
149 # Utilities
150 # -------------------------------------------------------------------------------
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
151 def run(*args)
0b6c86f6 »
2011-03-04 Add a --verbose option, and don't show executed commands without it
152 puts "Running: #{args.inspect}" if OPTIONS[:verbose]
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
153 system(*args) || raise("Failed to run: #{args.inspect}")
154 end
155
e6ddd9e1 » kerneis
2010-03-09 Strip invalid byte sequences from input
156 # cf. Paul Battley, http://po-ru.com/diary/fixing-invalid-utf-8-in-ruby-revisited/
157 def validate_utf8(s)
158 return Iconv.iconv('UTF-8//IGNORE', 'UTF-8', (s + ' ') ).first[0..-2]
159 end
160
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
161 def output_of(*args)
0b6c86f6 »
2011-03-04 Add a --verbose option, and don't show executed commands without it
162 puts "Running: #{args.inspect}" if OPTIONS[:verbose]
57782975 »
2010-08-24 Use Shellwords to more reliably escape subprocess arguments
163 output = IO.popen(args.map {|a| Shellwords.shellescape(a) }.join(' '), 'r') { |p| p.read }
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
164 if $?.exitstatus == 0
e6ddd9e1 » kerneis
2010-03-09 Strip invalid byte sequences from input
165 return validate_utf8(output)
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
166 else
167 raise "Failed to run: #{args.inspect}"
168 end
169 end
170
a110c04f »
2008-05-11 Provide and use Symbol#to_proc
171 class Symbol
172 def to_proc() lambda { |o| o.send(self) } end
173 end
174
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
175 class String
bd442b41 »
2008-05-10 Move DarcsPatch#decode_darcs_escape to String#darcs_unescape
176 def darcs_unescape
177 # darcs uses '[_\hh_]' to quote non-ascii characters where 'h' is
178 # a hexadecimal. We translate this to '=hh' and use ruby's unpack
179 # to do replace this with the proper byte.
1c8cccb2 »
2011-02-01 Fix an error where =NN character sequences in patch comments were wro…
180 gsub(/\[\_\\(..)\_\]/) { |x| "=#{$1}".unpack("M*")[0] }
bd442b41 »
2008-05-10 Move DarcsPatch#decode_darcs_escape to String#darcs_unescape
181 end
182 end
183
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
184
185 # -------------------------------------------------------------------------------
186 # Map darcs authors to git authors
187 # -------------------------------------------------------------------------------
188 class AuthorMap < Hash
189 attr_accessor :default_email
e6dbc648 » thomie
2010-08-13 Add default_author option.
190 attr_accessor :default_author
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
191
192 def self.load(filename)
193 new.merge(YAML.load_file(filename))
194 end
195
196 # gives the name and email
197 def [](author)
198 name_and_email(super || author)
199 end
200
201 private
202
203 def name_and_email(author)
40bb3629 »
2008-05-12 Tidy up author/email regex code
204 case author
205 when /^\s*(\S.*?)\s*\<(\S+@\S+?)\>\s*$/
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
206 [$1, $2]
40bb3629 »
2008-05-12 Tidy up author/email regex code
207 when /^\s*\<?(\S+@\S+?)\>?\s*$/
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
208 email = $1
209 [email.split('@').first, email]
e6dbc648 » thomie
2010-08-13 Add default_author option.
210 when ''
211 [default_author, default_email]
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
212 else
213 [author, default_email]
214 end
215 end
216 end
217
c8bfc117 »
2008-05-11 Replace $darcs_patches_in_git with CommitHistory class
218 # -------------------------------------------------------------------------------
219 # Storing a history of related darcs and git commits
220 # -------------------------------------------------------------------------------
221
222 class CommitHistory
223 def initialize(patch_file_name)
224 @patch_file_name = patch_file_name
3de38365 »
2008-05-12 Smoothly convert existing "darcs-hash:" metadata into the new-style Y…
225 @darcs_patches_in_git = {}
226 if File.exists?(patch_file_name)
227 @darcs_patches_in_git = YAML.load_file(patch_file_name)
228 unless @darcs_patches_in_git.is_a?(Hash)
229 raise "yaml hash not found in #{patch_file_name}"
230 end
231 else
ae775b5a »
2008-05-12 Return to storing darcs-hash in commit comments, but provide an optio…
232 # TODO: consider doing this unconditionally, since that
233 # might allow merging between repositories created with darcs-to-git
3de38365 »
2008-05-12 Smoothly convert existing "darcs-hash:" metadata into the new-style Y…
234 fill_from_darcs_hash_comments
235 end
c8bfc117 »
2008-05-11 Replace $darcs_patches_in_git with CommitHistory class
236 end
237
238 def record_git_commit(commit_id, identifier)
239 # using one file per darcs patch would be an incredible waste of space
240 # on my system one file takes up 4K even if only a few bytes are in it
241 # hence we just use a simple YAML hash
242 @darcs_patches_in_git[identifier] = commit_id
3de38365 »
2008-05-12 Smoothly convert existing "darcs-hash:" metadata into the new-style Y…
243 File.open(@patch_file_name, 'w') do |f|
244 YAML.dump(@darcs_patches_in_git, f)
c8bfc117 »
2008-05-11 Replace $darcs_patches_in_git with CommitHistory class
245 end
246 end
247
248 def find_git_commit(is_tag, git_tag_name, identifier)
61e337eb »
2012-01-09 Skip darcs tags applied to empty repos; record commit IDs for tags to…
249 @darcs_patches_in_git[identifier] ||
ffd9c8df »
2008-05-12 Tidy up consistency check code, and fix some unidiomatic constructions
250 if is_tag
6c83a4ef » sunaku
2008-09-21 Prevent error when copying first darcs 2 tag to git 1.6 repo
251 (output_of("git", "tag", "-l") rescue "").split(/\r?\n/).include?(git_tag_name) &&
38d026d5 »
2008-08-25 Use "git subcommand" rather than "git-subcommand", for git 1.6 compat…
252 output_of("git", "rev-list", "--max-count=1", "tags/#{git_tag_name}").strip
c8bfc117 »
2008-05-11 Replace $darcs_patches_in_git with CommitHistory class
253 end
254 end
c6a18813 »
2008-05-12 Use a more reliable trick to determine if the git repo is empty
255
256 def empty_repo?
257 !system("git rev-parse --verify HEAD >/dev/null 2>&1")
258 end
3de38365 »
2008-05-12 Smoothly convert existing "darcs-hash:" metadata into the new-style Y…
259
15c7ac6a » thomie
2010-08-15 Check only once if git repo is empty. Faster.
260 private
261
3de38365 »
2008-05-12 Smoothly convert existing "darcs-hash:" metadata into the new-style Y…
262 def fill_from_darcs_hash_comments
263 return if empty_repo?
d31f5290 »
2010-08-24 Fix typo in use of --no-color arg to git
264 Array(output_of("git", "log", "--grep=darcs-hash:", "--no-color").split(/^commit /m)[1..-1]).each do |entry|
3de38365 »
2008-05-12 Smoothly convert existing "darcs-hash:" metadata into the new-style Y…
265 commit_id, identifier = entry.scan(/^([a-z0-9]+$).*darcs-hash:(.*?)$/sm).flatten
266 record_git_commit(commit_id, identifier)
267 end
268 end
c8bfc117 »
2008-05-11 Replace $darcs_patches_in_git with CommitHistory class
269 end
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
270
271 # -------------------------------------------------------------------------------
272 # Reading darcs patches and applying them to a git repo
273 # -------------------------------------------------------------------------------
274
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
275 class DarcsPatch
9685ea29 »
2007-10-28 Include patch comment as well as just name (thanks Antti-Juhani Kaija…
276 attr_accessor :source_repo, :author, :date, :inverted, :identifier, :name, :is_tag, :git_tag_name, :comment
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
277 attr_reader :git_author_name, :git_author_email
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
278
279 def initialize(source_repo, patch_xml)
280 self.source_repo = source_repo
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
281 self.author = patch_xml.attribute('author').value.darcs_unescape
c547c011 » nominolo
2008-05-07 Proper handling of timezones
282 self.date = darcs_date_to_git_date(patch_xml.attribute('date').value,
283 patch_xml.attribute('local_date').value)
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
284 self.inverted = (patch_xml.attribute('inverted').to_s == 'True')
285 self.identifier = patch_xml.attribute('hash').to_s
bd442b41 »
2008-05-10 Move DarcsPatch#decode_darcs_escape to String#darcs_unescape
286 self.name = patch_xml.get_elements('name').first.get_text.value.darcs_unescape rescue 'Unnamed patch'
287 self.comment = patch_xml.get_elements('comment').first.get_text.value.darcs_unescape rescue nil
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
288 if (self.is_tag = (self.name =~ /^TAG (.*)/))
8f171f79 »
2011-07-30 Convert git-check-ref-format logic into a single regexp
289 self.git_tag_name = self.safe_patch_name($1)
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
290 end
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
291 @git_author_name, @git_author_email = AUTHOR_MAP[author]
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
292 end
293
8f171f79 »
2011-07-30 Convert git-check-ref-format logic into a single regexp
294 def safe_patch_name(darcs_name)
295 # See 'man git-check-ref-format'
0be8ed0c »
2012-02-06 More strictly limit tag formats, according to git-check-ref-format (f…
296 darcs_name.gsub(/\/+/, '/').gsub(/(?:[\s~\^\\:*\?\[]+|\.{2,}|\#\{|^\.|\.$|^\/|\/$|[^\040-\177])/, '_').gsub(/_+/, '_')
8f171f79 »
2011-07-30 Convert git-check-ref-format logic into a single regexp
297 end
298
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
299 def <=>(other)
300 self.identifier <=> other.identifier
301 end
302
303 def git_commit_message
4f0a3fd7 » caldwell
2010-03-18 Make --clean-commit-messages also remove darcs' ugly "Ignore-This" he…
304 patch_name = ((inverted ? "UNDO: #{name}" : name) unless name =~ /^\[\w+ @ \d+\]/)
305 OPTIONS[:clean_commit_messages] ? [ patch_name, comment && comment.gsub(/^Ignore-this:.*$/, '')].compact.join("\n") \
306 : [ patch_name, comment, "darcs-hash:#{identifier}" ].compact.join("\n\n")
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
307 end
308
309 def self.read_from_repo(repo)
7220bb8e » nominolo
2008-05-09 Cosmetics
310 REXML::Document.new(output_of("darcs", "changes", "--reverse",
e3692279 »
2011-03-03 Support mirroring remote darcs repos directly, without having to crea…
311 "--repo=#{repo}", "--xml",
6133a71e » thomie
2010-08-15 Use darcs changes --no-summary.
312 "--no-summary")).
7220bb8e » nominolo
2008-05-09 Cosmetics
313 get_elements('changelog/patch').map do |p|
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
314 DarcsPatch.new(repo, p)
315 end
316 end
317
318 # Return committish for corresponding patch in current git repo, or false/nil
319 def id_in_git_repo
32c084fc » thomie
2010-08-15 Check only once if commit already in git repo.
320 COMMIT_HISTORY.find_git_commit(is_tag, git_tag_name, identifier)
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
321 end
322
323 def pull_and_apply
324 puts "\n" + ("=" * 80)
0b6c86f6 »
2011-03-04 Add a --verbose option, and don't show executed commands without it
325 puts "PATCH : #{name}" ## "1 of 43"
f76d7f22 » Steve
2007-10-17 Better handling for darcs changeset authors in rfc822 format ("blah <…
326 puts "DATE : #{date}"
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
327 puts "AUTHOR: #{author} => #{git_author_name} <#{git_author_email}>"
0b6c86f6 »
2011-03-04 Add a --verbose option, and don't show executed commands without it
328 puts "-" * 80
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
329
330 pull
0b6c86f6 »
2011-03-04 Add a --verbose option, and don't show executed commands without it
331 puts output_of("git", "status", "--short") unless OPTIONS[:quiet]
6d8c8577 »
2008-05-12 Check that darcs reports the working area as clean before pulling the…
332 commit_to_git_repo
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
333 end
334
335 private
336
337 def pull
110ec156 » thomie
2010-08-15 Add no-check option. Runs 2x faster on testrepo.
338 if OPTIONS[:do_checks] and not darcs_reports_clean_repo?
6d8c8577 »
2008-05-12 Check that darcs reports the working area as clean before pulling the…
339 raise "Darcs reports dirty repo before pulling #{identifier}; confused, so aborting"
340 end
7220bb8e » nominolo
2008-05-09 Cosmetics
341 run("darcs", "pull", "--all", "--quiet",
342 "--match", "hash #{identifier}",
3687cd01 »
2011-03-03 Set default darcs repo when pulling
343 "--set-scripts-executable", "--set-default", source_repo)
eebba917 »
2011-03-04 Whitespace cleanup
344 if OPTIONS[:do_checks] and not darcs_reports_clean_repo?
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
345 puts "Darcs reports dirty directory: assuming conflict that is fixed by a later patch... reverting"
346 run("darcs revert --all")
e86c9c03 »
2011-07-19 More aggressively clear out darcs backup files when importing conflic…
347 run("find . -name '*-darcs-backup[0-9]' -exec rm -rf {} \\;") # darcs2 creates these
8cdff36e » thomie
2010-08-15 Do third check for clean directory only if needed.
348 unless darcs_reports_clean_repo?
39f0e062 » smcv
2008-07-10 Fix repository cleanup after pull
349 system("darcs whatsnew -sl")
350 raise "Failed to clean repo, see above"
8cdff36e » thomie
2010-08-15 Do third check for clean directory only if needed.
351 end
39f0e062 » smcv
2008-07-10 Fix repository cleanup after pull
352 end
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
353 end
354
6d8c8577 »
2008-05-12 Check that darcs reports the working area as clean before pulling the…
355 def darcs_reports_clean_repo?
2c824617 » adrianlang
2010-05-11 Ignore the 'darcs_testing_for_nfs' dir created by darcs in repos on N…
356 `darcs whatsnew -sl | egrep -v '^a (\./)?\.git(/|$)' | egrep -v '^a ./darcs_testing_for_nfs/$'` =~ /^(No changes!)?$/
6d8c8577 »
2008-05-12 Check that darcs reports the working area as clean before pulling the…
357 end
358
61e337eb »
2012-01-09 Skip darcs tags applied to empty repos; record commit IDs for tags to…
359 def latest_commit_id
360 git_repo_empty? ? 'NONE' : output_of("git", "rev-list", "-n1", "--no-color", "HEAD").scan(/^([a-z0-9]+)$/).flatten.first
361 end
362
363 def git_repo_empty?
364 output_of("git", "branch").strip == ''
365 end
366
6d8c8577 »
2008-05-12 Check that darcs reports the working area as clean before pulling the…
367 def commit_to_git_repo
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
368 ENV['GIT_AUTHOR_NAME'] = ENV['GIT_COMMITTER_NAME'] = git_author_name
369 ENV['GIT_AUTHOR_EMAIL'] = ENV['GIT_COMMITTER_EMAIL'] = git_author_email
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
370 ENV['GIT_AUTHOR_DATE'] = ENV['GIT_COMMITTER_DATE'] = date
371 if is_tag
61e337eb »
2012-01-09 Skip darcs tags applied to empty repos; record commit IDs for tags to…
372 if git_repo_empty?
373 STDERR.write("Can't tag an empty git repo: skipping tag '#{git_tag_name}'\n")
374 else
375 run("git", "tag", "-a", "-f", "-m", git_commit_message, git_tag_name)
376 end
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
377 else
952ddd72 »
2011-03-03 Avoid running "git ls-files" twice per commit
378 new_files, changed_files = git_ls_files
379 if new_files.any?
53f23cce » jmah
2009-08-29 Add files even if they would be ignored by git
380 run(*(["git", "add", "-f"] + new_files))
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
381 end
952ddd72 »
2011-03-03 Avoid running "git ls-files" twice per commit
382 if changed_files.any? || new_files.any?
8c354797 » thomie
2010-08-15 Add --no-verbose options and show progress.
383 output_of("git", "commit", "-a", "-m", git_commit_message)
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
384 end
385 end
61e337eb »
2012-01-09 Skip darcs tags applied to empty repos; record commit IDs for tags to…
386 # get full id of last commit and associate it with the patch id
387 COMMIT_HISTORY.record_git_commit(latest_commit_id, identifier)
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
388 end
389
c547c011 » nominolo
2008-05-07 Proper handling of timezones
390 def darcs_date_to_git_date(utc,local)
7a488be6 » nominolo
2008-05-09 Improve documentation for timezone extraction
391 # Calculates a git-friendly date (e.g., timezone CET decribed as
392 # +0100) by using the two date fields that darcs gives us: a list
393 # of numbers describing the UTC time and a local time formatted in
394 # a human-readable format. We could parse the local time and
395 # derive the timezone offset from the timezone name. but timezones
396 # aren't well-defined, so we ignore the timezone name and instead
397 # calculate the timezone offset ourselves by calculating the
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
398 # difference between local time and UTC time.
ffd9c8df »
2008-05-12 Tidy up consistency check code, and fix some unidiomatic constructions
399 if not utc =~ /^(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/
c547c011 » nominolo
2008-05-07 Proper handling of timezones
400 raise "Wrong darcs date format"
401 end
402 utc_time = Time.utc($1,$2,$3,$4,$5,$6)
7a488be6 » nominolo
2008-05-09 Improve documentation for timezone extraction
403 # example: Mon Oct 2 14:23:28 CEST 2006
404 # everything except timezone name is fixed-length, if parsing
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
405 # fails we just use UTC
7a488be6 » nominolo
2008-05-09 Improve documentation for timezone extraction
406 pat = /^\w\w\w (\w\w\w) ([ 1-9]\d) ([ 0-9]\d)\:(\d\d)\:(\d\d) \w* (\d\d\d\d)/
ffd9c8df »
2008-05-12 Tidy up consistency check code, and fix some unidiomatic constructions
407 local_time = if pat =~ local
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
408 Time.utc($6,$1,$2,$3,$4,$5)
409 else
410 utc_time
411 end
7a488be6 » nominolo
2008-05-09 Improve documentation for timezone extraction
412 offs = local_time - utc_time # time offset in seconds
c547c011 » nominolo
2008-05-07 Proper handling of timezones
413 t = local_time
7a488be6 » nominolo
2008-05-09 Improve documentation for timezone extraction
414 # formats the above example as: 2006-10-02 14:23:28 +0200
415 s = sprintf("%4d-%02d-%02d %02d:%02d:%02d %s%02d%02d",
416 t.year, t.month, t.day,
c547c011 » nominolo
2008-05-07 Proper handling of timezones
417 t.hour, t.min, t.sec,
7a488be6 » nominolo
2008-05-09 Improve documentation for timezone extraction
418 offs < 0 ? "-" : "+", offs.abs/3600, offs.abs.modulo(3600)/60 )
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
419 end
420
952ddd72 »
2011-03-03 Avoid running "git ls-files" twice per commit
421 def git_ls_files
422 summary = output_of(*["git", "ls-files", "-t", "-o", "-m", "-d", "-z", "-X", ".git/info/exclude"])
423 new_files, changed_files = [%w(?), %w(R C)].map do |wanted|
424 summary.scan(/(.?) (.*?)\0/m).map do |code, name|
425 name if wanted.include?(code)
426 end.compact
427 end
4f630f35 »
2007-10-27 Improved parsing of git-ls-files output, which changed with a git rel…
428 end
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
429 end
430
76cbfc22 » nominolo
2008-05-09 Allow listing of authors
431 def extract_authors(patches)
432 unique_authors = {}
433 patches.each do |p|
434 unique_authors[p.author] =
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
435 "#{p.git_author_name}" + (p.git_author_email.nil? ? "" : " <#{p.git_author_email}>")
76cbfc22 » nominolo
2008-05-09 Allow listing of authors
436 end
437 puts "# You can use the following output as a starting point for an author_map"
438 puts "# Just fill in the proper text after the colon; put email addresses in"
439 puts "# angle brackets. You can remove any lines that look OK to you."
440 # TODO: Can we make the output sorted?
441 puts YAML::dump( unique_authors )
442 end
443
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
444
445 # -------------------------------------------------------------------------------
446 # Pre-flight checks
447 # -------------------------------------------------------------------------------
448
bfa117a2 »
2010-12-20 Make version detection handle darcs 2.5, ie. don't assume a three-par…
449 DARCS_VERSION = output_of(*%w(darcs -v)).scan(/(\d+)\.(\d+)(?:\.(\d+))?/).flatten.map {|v| v.to_i}
b88ae01e » sunaku
2008-09-21 Add support for darcs2 repositories.
450
451 def darcs2_repo?(repo)
8cad3633 »
2011-03-04 Improve darcs repo version detection
452 if File.exist?(repo) # Local repo
e3692279 »
2011-03-03 Support mirroring remote darcs repos directly, without having to crea…
453 begin
454 output_of("darcs", "show", "repo", "--repo=#{repo}") =~ /Format:.*darcs-2/
455 rescue # darcs1 does not have a "show" command, so we get an exception
456 false
457 end
8cad3633 »
2011-03-04 Improve darcs repo version detection
458 else
6483d1fe »
2011-03-04 Don't fail if remote upstream repo has no _darcs/format file
459 format_file = open(repo.scan(/^(.*?)\/?$/).flatten.first + "/_darcs/format") { |f| f.read } rescue nil
1e3ba54c »
2011-03-04 Fix identification of remote repository formats
460 return format_file && (format_file =~ /darcs-2(?:\.|$)/)
b88ae01e » sunaku
2008-09-21 Add support for darcs2 repositories.
461 end
462 end
463
4cce98fe »
2008-02-22 Add darcs version check and warning, due to known issues with darcs 1…
464 class Array; include Comparable; end
465
11ffabe8 »
2008-11-22 Properly initialise conversion repo when converting old-format darcs …
466 unless DARCS_VERSION > [1, 0, 7]
4cce98fe »
2008-02-22 Add darcs version check and warning, due to known issues with darcs 1…
467 STDERR.write("WARNING: your darcs appears to be old, and may not work with this script\n")
468 end
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
469
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
470
471 # -------------------------------------------------------------------------------
472 # Initialise the working area
473 # -------------------------------------------------------------------------------
bf4f1baa »
2008-11-22 Set PAGER / GIT_PAGER to 'cat' globally (thanks Samium Gromoff)
474 ENV['GIT_PAGER'] = ENV['PAGER'] = "cat" # so that pager of git-log doesn't halt conversion
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
475
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
476 unless File.directory?("_darcs")
3de38365 »
2008-05-12 Smoothly convert existing "darcs-hash:" metadata into the new-style Y…
477 puts "Initialising the working area."
b88ae01e » sunaku
2008-09-21 Add support for darcs2 repositories.
478
2edca09c »
2011-03-04 Allow user to pre-init git repository if desired.
479 if Dir.entries(Dir.pwd).delete_if { |e| e == ".git" }.size != 2
110ec156 » thomie
2010-08-15 Add no-check option. Runs 2x faster on testrepo.
480 raise "Directory not empty. Aborting"
481 end
2edca09c »
2011-03-04 Allow user to pre-init git repository if desired.
482 if File.directory?(".git")
483 puts "Detected pre-created git repository. If this is not an empty repo, you may encounter problems."
484 else
485 puts "Initializing git repo"
486 run("git", "init")
487 end
110ec156 » thomie
2010-08-15 Add no-check option. Runs 2x faster on testrepo.
488
b88ae01e » sunaku
2008-09-21 Add support for darcs2 repositories.
489 darcs_init = %w(darcs init)
11ffabe8 »
2008-11-22 Properly initialise conversion repo when converting old-format darcs …
490 if darcs2_repo?(SRCREPO)
491 darcs_init << "--darcs-2"
492 elsif DARCS_VERSION >= [2, 0, 0]
563a8682 »
2011-03-04 Show when old darcs format is being used
493 puts "Using legacy darcs inventory format to match upstream repo"
af69a468 » kmels
2012-06-05 darcs2.8.1 doesn't recognize --old-fashioned-inventory anymore, use -…
494 if DARCS_VERSION >= [2, 8, 1]
495 darcs_init << "--hashed"
496 else
497 darcs_init << "--old-fashioned-inventory"
498 end
11ffabe8 »
2008-11-22 Properly initialise conversion repo when converting old-format darcs …
499 end
b88ae01e » sunaku
2008-09-21 Add support for darcs2 repositories.
500 run(*darcs_init)
501
19b2143a »
2011-03-03 Create .git/info/exclude ourselves if "git init" doesn't, e.g. becaus…
502 FileUtils.mkdir_p(".git/info")
503 File.open(".git/info/exclude", "a+") { |f| f.write("_darcs\n.DS_Store\n") }
518b74a4 » jmah
2009-08-29 Add borings to the global darcs boring file
504
505 # Patterns to exclude
506 git_borings = [] << '(^|/)\.git($|/)' << '(^|/)\.DS_Store$'
507 existing_borings = []
508
509 # Check existing global boring patterns
510 global_darcs_dir = Pathname.new("#{ENV['HOME']}/.darcs")
511 global_boring_file = global_darcs_dir + 'boring'
512 if global_boring_file.exist?
513 existing_borings = File.open(global_boring_file, 'r') {|f| f.readlines}.map {|l| l.chomp }
514 else
515 global_darcs_dir.mkdir unless global_darcs_dir.directory?
516 end
517
518 # Add boring patterns to global boring file
519 File.open(global_boring_file, 'a') do |f|
520 (git_borings - existing_borings).each {|b| f.puts b }
521 end
522
7f35b89e » nominolo
2008-05-09 Add TODO
523 # TODO: migrate darcs borings into git excludes?
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
524 end
525
3de38365 »
2008-05-12 Smoothly convert existing "darcs-hash:" metadata into the new-style Y…
526
527 COMMIT_HISTORY = CommitHistory.new(GIT_PATCHES)
528
87433cc0 » Steve
2007-09-12 Initial version, working for single-branch imports with tags
529
ffd9c8df »
2008-05-12 Tidy up consistency check code, and fix some unidiomatic constructions
530 AUTHOR_MAP = if OPTIONS[:author_map]
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
531 AuthorMap.load(OPTIONS[:author_map])
532 elsif File.exists?(DEFAULT_AUTHOR_MAP_FILE)
533 AuthorMap.load(DEFAULT_AUTHOR_MAP_FILE)
534 else
535 AuthorMap.new
536 end
e6dbc648 » thomie
2010-08-13 Add default_author option.
537 AUTHOR_MAP.default_author = OPTIONS[:default_author]
0bfb3332 »
2008-05-11 Some tidyup work, particularly regarding author maps
538 AUTHOR_MAP.default_email = OPTIONS[:default_email]
ca12ee3d » nominolo
2008-05-09 Remember author substitition map
539
c8bfc117 »
2008-05-11 Replace $darcs_patches_in_git with CommitHistory class
540
38670d8c » Steve
2007-09-17 Support incremental pulling when some old patches were no-ops (e.g. e…
541 patches = DarcsPatch.read_from_repo(SRCREPO)
ffd9c8df »
2008-05-12 Tidy up consistency check code, and fix some unidiomatic constructions
542 if OPTIONS[:list_authors]
76cbfc22 » nominolo
2008-05-09 Allow listing of authors
543 extract_authors(patches)
544 exit(0)
545 end
38670d8c » Steve
2007-09-17 Support incremental pulling when some old patches were no-ops (e.g. e…
546
15c7ac6a » thomie
2010-08-15 Check only once if git repo is empty. Faster.
547 if COMMIT_HISTORY.empty_repo?
548 patches_available = patches
549 else
550 patches_available = patches.find_all { |p| not p.id_in_git_repo }
38670d8c » Steve
2007-09-17 Support incremental pulling when some old patches were no-ops (e.g. e…
551 end
552
f5bf94d8 »
2008-05-12 Clean up logic linking --patches option and running of post-flight co…
553 patches_to_pull = if OPTIONS[:num_patches]
554 patches_available.first(OPTIONS[:num_patches])
555 else
556 patches_available
557 end
abbefc55 » nominolo
2008-05-09 Allow limiting the number of patches to pull
558
8c354797 » thomie
2010-08-15 Add --no-verbose options and show progress.
559 original_stdout = $stdout
0b6c86f6 »
2011-03-04 Add a --verbose option, and don't show executed commands without it
560 if OPTIONS[:quiet]
8c354797 » thomie
2010-08-15 Add --no-verbose options and show progress.
561 # Capture all writes to stdout.
562 $stdout = StringIO.new
563 end
564
565 patches_to_pull.each_with_index { |p, i|
0b6c86f6 »
2011-03-04 Add a --verbose option, and don't show executed commands without it
566 original_stdout.puts "\nImporting patch #{i+1} of #{patches_to_pull.size}:"
8c354797 » thomie
2010-08-15 Add --no-verbose options and show progress.
567 p.pull_and_apply
568 }
569
570 $stdout = original_stdout
a1fe6014 » nominolo
2008-05-07 Hint at the usefulness of 'git gc'
571
ffd9c8df »
2008-05-12 Tidy up consistency check code, and fix some unidiomatic constructions
572 pulled = patches_to_pull.size
573 if pulled == 0
574 puts "\nNothing to pull."
575 else
576 puts "\nPulled #{pulled} patch#{"es" unless pulled == 1}."
577 puts "\nDarcs import successful! You may now want to run `git gc' to
939371a2 »
2010-08-24 Fix typo in message providing hint about "git gc"
578 optimize space usage of the git repo"
a6b9f7ef » nominolo
2008-05-07 Add consistency check after import.
579 end
580
f5bf94d8 »
2008-05-12 Clean up logic linking --patches option and running of post-flight co…
581
582 # -------------------------------------------------------------------------------
583 # Post-flight checks
584 # -------------------------------------------------------------------------------
585
586 # if we didn't pull all patches, then the consistency check would
587 # fail, so we simply skip it
588 if patches_to_pull.size == patches_available.size
e3692279 »
2011-03-03 Support mirroring remote darcs repos directly, without having to crea…
589 if File.exist?(SRCREPO)
590 puts "Comparing final state with source repo..."
591 system("diff", "-ur", "-x", "_darcs", "-x", ".git", ".", SRCREPO)
592 if $? != 0
593 abort <<-end_msg
ffd9c8df »
2008-05-12 Tidy up consistency check code, and fix some unidiomatic constructions
594 !!! There were differences! See diff above for details.
595 !!! It may be that the source repository was dirty.
596 !!! Run "cd #{SRCREPO} && darcs whatsnew -sl" to check.
e3692279 »
2011-03-03 Support mirroring remote darcs repos directly, without having to crea…
597 end_msg
480e8f04 »
2011-03-03 Print a reassuring message when contents of original and converted re…
598 else
599 puts "Contents match."
e3692279 »
2011-03-03 Support mirroring remote darcs repos directly, without having to crea…
600 end
601 else
602 puts "Warning: source repo is not local, so we can't compare final git state with latest darcs contents."
ffd9c8df »
2008-05-12 Tidy up consistency check code, and fix some unidiomatic constructions
603 end
604 end
Something went wrong with that request. Please try again.