darcs-ruby 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +51 -0
- data/bin/darcs-import +72 -0
- data/lib/darcs/patchinfo.rb +78 -0
- data/lib/darcs/patchwriter.rb +138 -0
- data/lib/darcs/repository.rb +129 -0
- data/test/darcs-import_test.rb +39 -0
- data/test/patchinfo_test.rb +53 -0
- data/test/patchwriter_test.rb +86 -0
- data/test/repository_test.rb +96 -0
- data/test/test_helper.rb +72 -0
- metadata +54 -0
data/Rakefile
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rake'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
require 'rake/gempackagetask'
|
7
|
+
|
8
|
+
PRG_VERSION = '0.0.1'
|
9
|
+
PRG_TEST_FILES = FileList['test/**/*_test.rb']
|
10
|
+
|
11
|
+
task :default => :test
|
12
|
+
|
13
|
+
Rake::TestTask.new do |t|
|
14
|
+
t.libs << 'lib'
|
15
|
+
t.libs << 'test'
|
16
|
+
t.test_files = PRG_TEST_FILES
|
17
|
+
t.verbose = true
|
18
|
+
end
|
19
|
+
|
20
|
+
Rake::RDocTask.new do |rdoc|
|
21
|
+
rdoc.rdoc_dir = 'doc'
|
22
|
+
rdoc.title = "Ruby Darcs -- Ruby interface to Darcs change control"
|
23
|
+
rdoc.options << '--line-numbers --inline-source'
|
24
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
25
|
+
end
|
26
|
+
|
27
|
+
gem_spec = Gem::Specification.new do |s|
|
28
|
+
s.platform = Gem::Platform::RUBY
|
29
|
+
s.name = 'darcs-ruby'
|
30
|
+
s.summary = "Interface to Darcs change control system"
|
31
|
+
s.version = PRG_VERSION
|
32
|
+
s.author = "Jason M. Felice"
|
33
|
+
s.email = "jfelice@cronosys.com"
|
34
|
+
s.homepage = "http://eraserhead.net/darcs/darcs-ruby/doc/"
|
35
|
+
s.has_rdoc = true
|
36
|
+
s.files = FileList["lib/**/*", "test/**/*", "Rakefile", "bin/*"]
|
37
|
+
s.test_files = PRG_TEST_FILES
|
38
|
+
s.bindir = 'bin'
|
39
|
+
s.executables = [ 'darcs-import' ]
|
40
|
+
end
|
41
|
+
|
42
|
+
Rake::GemPackageTask.new(gem_spec) do |p|
|
43
|
+
p.need_tar = true
|
44
|
+
p.need_zip = true
|
45
|
+
end
|
46
|
+
|
47
|
+
task :install => :package do
|
48
|
+
sh 'gem install ./pkg/darcs-ruby-0.0.1.gem'
|
49
|
+
end
|
50
|
+
|
51
|
+
# vi:set sts=2 sw=2 ai et:
|
data/bin/darcs-import
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
#
|
3
|
+
# = darcs-import
|
4
|
+
#
|
5
|
+
# Script to start a large repository from a source tree. This script takes
|
6
|
+
# shortcuts because darcs' apparent run time for recording patches is O(n^2)
|
7
|
+
#
|
8
|
+
|
9
|
+
# Enable us to run from the source tree
|
10
|
+
$:.push(File.join(File.dirname(File.dirname(__FILE__)),'lib'))
|
11
|
+
|
12
|
+
require 'rubygems'
|
13
|
+
require 'darcs/repository'
|
14
|
+
require 'darcs/patchinfo'
|
15
|
+
require 'darcs/patchwriter'
|
16
|
+
require 'find'
|
17
|
+
|
18
|
+
include Darcs
|
19
|
+
|
20
|
+
repo = Repository.find
|
21
|
+
if repo.nil?
|
22
|
+
system 'darcs initialize'
|
23
|
+
repo = Repository.find
|
24
|
+
elsif repo.patches.count > 0
|
25
|
+
raise "Must be used on an empty repository!"
|
26
|
+
end
|
27
|
+
|
28
|
+
raise "Set $EMAIL first!" if !ENV['EMAIL']
|
29
|
+
patch_info = PatchInfo.new(Time.now, 'Initial import', ENV['EMAIL'])
|
30
|
+
repo.write_patch(patch_info) do |writer|
|
31
|
+
Find.find('.') do |entry|
|
32
|
+
next if entry == '.'
|
33
|
+
next if repo.boring?(entry)
|
34
|
+
Find.prune if !FileTest.directory?(entry)
|
35
|
+
writer << Chunk::AddDirectory.new(entry)
|
36
|
+
dstdir = File.join(repo.path,'_darcs','current',entry)
|
37
|
+
Dir.mkdir(dstdir)
|
38
|
+
end
|
39
|
+
Find.find('.') do |entry|
|
40
|
+
next if repo.boring?(entry)
|
41
|
+
if !FileTest.directory?(entry)
|
42
|
+
writer << Chunk::AddFile.new(entry)
|
43
|
+
dstfile = File.join(repo.path,'_darcs','current',entry)
|
44
|
+
File.open(entry, 'r') do |f|
|
45
|
+
File.open(dstfile,'w') do |d|
|
46
|
+
if repo.binary?(entry)
|
47
|
+
f.binmode
|
48
|
+
contents = f.read
|
49
|
+
writer << Chunk::Binary.new(entry, '', contents)
|
50
|
+
d.write(contents)
|
51
|
+
else
|
52
|
+
data = f.read
|
53
|
+
d.write(data)
|
54
|
+
if data == "\n"
|
55
|
+
hunk = "+\n"
|
56
|
+
elsif data.size > 0 && data[-1..-1] != "\n"
|
57
|
+
hunk = "-\n" + data.split("\n",-1).map{|line| '+' + line}.join("\n") + "\n"
|
58
|
+
else
|
59
|
+
hunk = data[0..-2].split("\n",-1).map{|line| '+' + line}.join("\n") + "\n"
|
60
|
+
end
|
61
|
+
writer << Chunk::Hunk.new(entry, 1, hunk)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
File.utime(0, File.mtime(entry), dstfile)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
system "cp _darcs/patches/#{patch_info.filename} /tmp/foo.gz"
|
72
|
+
|
@@ -0,0 +1,78 @@
|
|
1
|
+
|
2
|
+
require 'sha1'
|
3
|
+
|
4
|
+
module Darcs
|
5
|
+
|
6
|
+
# This class holds the patch's name, log, author, date, and other
|
7
|
+
# meta-info.
|
8
|
+
class PatchInfo
|
9
|
+
def initialize(date, name, author, log = nil, inverted = false)
|
10
|
+
if date.kind_of?(String)
|
11
|
+
@date = parse_date(date)
|
12
|
+
else
|
13
|
+
@date = date
|
14
|
+
end
|
15
|
+
@name = name
|
16
|
+
@author = author
|
17
|
+
@log = log
|
18
|
+
@inverted = inverted
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :date, :name, :author, :log
|
22
|
+
def inverted?
|
23
|
+
@inverted
|
24
|
+
end
|
25
|
+
|
26
|
+
# Reads a patch from a stream using the inventory format
|
27
|
+
def self.read(f)
|
28
|
+
line = f.gets
|
29
|
+
return nil if line.nil?
|
30
|
+
if line[0..0] != '['
|
31
|
+
raise "Invalid inventory entry (starts with \"#{line[0..-2]}\")"
|
32
|
+
end
|
33
|
+
|
34
|
+
name = line[1..-2]
|
35
|
+
line = f.readline
|
36
|
+
raise "Invalid inventory entry" if !line[/^(.*)\*\*([0-9]{14})\]?\s*$/]
|
37
|
+
author = $1
|
38
|
+
date = $2
|
39
|
+
log = nil
|
40
|
+
if !line[/\]\s*$/]
|
41
|
+
log = ""
|
42
|
+
log += line[1..-1] while !((line = f.readline) =~ /^\]/)
|
43
|
+
end
|
44
|
+
|
45
|
+
return self.new(date, name, author, log)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Retrieve the patch's date in string timestamp format
|
49
|
+
def timestamp
|
50
|
+
date.strftime("%Y%m%d%H%M%S")
|
51
|
+
end
|
52
|
+
|
53
|
+
# Retrieve the patch's name
|
54
|
+
def filename
|
55
|
+
author_hash = SHA1.new(author).to_s[0..4]
|
56
|
+
hash = SHA1.new(name + author + timestamp +
|
57
|
+
(log.nil? ? '' : log.gsub(/\n/, '')) +
|
58
|
+
(inverted? ? 't' : 'f'))
|
59
|
+
"#{timestamp}-#{author_hash}-#{hash}.gz"
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_s
|
63
|
+
if log
|
64
|
+
the_log = log.gsub(/[\n\s]+$/, '').gsub(/\n/, "\n ")
|
65
|
+
end
|
66
|
+
"[#{name}\n#{author}**#{timestamp}" +
|
67
|
+
(log.nil? ? '' : "\n " + the_log + "\n") + "]"
|
68
|
+
end
|
69
|
+
|
70
|
+
protected
|
71
|
+
def parse_date(str)
|
72
|
+
# Format is YYYYMMDDHHMMSS
|
73
|
+
Time.gm(str[0..3].to_i, str[4..5].to_i, str[6..7].to_i, str[8..9].to_i,
|
74
|
+
str[10..11].to_i, str[12..13].to_i)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
|
2
|
+
require 'zlib'
|
3
|
+
|
4
|
+
module Darcs
|
5
|
+
|
6
|
+
# A PatchWriter is used to write PatchChunks into a patch.
|
7
|
+
class PatchWriter
|
8
|
+
|
9
|
+
# Create a new PatchWriter for writing the patch file associated with the
|
10
|
+
# given patch object
|
11
|
+
def initialize(patch)
|
12
|
+
@patch = patch
|
13
|
+
@file = File.open(patch.filename, 'w')
|
14
|
+
@gz = Zlib::GzipWriter.new(@file)
|
15
|
+
@gz.write(patch.info.to_s + " {\n")
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :patch
|
19
|
+
|
20
|
+
# Finishes writing the patch and close files
|
21
|
+
def finish
|
22
|
+
@gz.write("}\n")
|
23
|
+
@gz.close
|
24
|
+
end
|
25
|
+
|
26
|
+
# Closes files and deletes the patch file
|
27
|
+
def abort
|
28
|
+
begin
|
29
|
+
@gz.close
|
30
|
+
rescue
|
31
|
+
end
|
32
|
+
begin
|
33
|
+
File.delete(patch.filename)
|
34
|
+
rescue
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Writes a patch chunk to the file
|
39
|
+
def << (chunk)
|
40
|
+
chunk.write(@gz, patch)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
module Chunk
|
46
|
+
|
47
|
+
# Base class for other chunks
|
48
|
+
class Base
|
49
|
+
end
|
50
|
+
|
51
|
+
# Chunk representing the addition of a directory to a repository
|
52
|
+
class AddDirectory <Base
|
53
|
+
def initialize(path)
|
54
|
+
@path = path
|
55
|
+
end
|
56
|
+
|
57
|
+
attr_reader :path
|
58
|
+
|
59
|
+
def write(io, patch)
|
60
|
+
io.write("adddir #{path}\n")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Chunk which adds record of a file to the repository. The file contents
|
65
|
+
# are not a part of this; those must be added separately with Chunk::Hunk
|
66
|
+
# or Chunk::Binary.
|
67
|
+
class AddFile <Base
|
68
|
+
def initialize(path)
|
69
|
+
@path = path
|
70
|
+
end
|
71
|
+
|
72
|
+
attr_reader :path
|
73
|
+
|
74
|
+
def write(io, patch)
|
75
|
+
io.write("addfile #{path}\n")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Chunk which makes a modification to a text file. If the file is binary,
|
80
|
+
# you will need to use Darcs::Chunk::Binary instead
|
81
|
+
#
|
82
|
+
# FIXME: We should create aggregate chunks to do a lot of the foot work
|
83
|
+
# for diffing, what not. An AddFileWithData chunk, A DiffFile chunk,
|
84
|
+
# whatnot. Or maybe a different method will present itself?
|
85
|
+
#
|
86
|
+
class Hunk <Base
|
87
|
+
# Creates a new hunk chunk for the specified file and line.
|
88
|
+
def initialize(path, line, data)
|
89
|
+
@path = path
|
90
|
+
@line = line
|
91
|
+
@data = data
|
92
|
+
end
|
93
|
+
|
94
|
+
attr_reader :path, :line, :data
|
95
|
+
|
96
|
+
def write(io, patch)
|
97
|
+
io.write("hunk #{path} #{line}\n#{data}")
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Chunk which replaces a binary file's contents
|
102
|
+
class Binary <Base
|
103
|
+
|
104
|
+
ENCODED_LINE_LENGTH = 78
|
105
|
+
|
106
|
+
# Creates a new Binary chunk. Old and new data are in their binary
|
107
|
+
# (non-encoded) form.
|
108
|
+
def initialize(path, old, new)
|
109
|
+
@path = path
|
110
|
+
@old = old
|
111
|
+
@new = new
|
112
|
+
end
|
113
|
+
|
114
|
+
attr_reader :path, :old, :new
|
115
|
+
|
116
|
+
def write(io, patch)
|
117
|
+
io.write("binary #{path}\noldhex\n#{hex_encode old}newhex\n#{hex_encode new}")
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
def chunk(data, size)
|
122
|
+
block_max = (data.size - 1) / size
|
123
|
+
(0..block_max).map do |chunk_number|
|
124
|
+
data[(chunk_number * size)...((chunk_number + 1) * size)]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def hex_encode(data)
|
129
|
+
return '' if data.size == 0
|
130
|
+
chunk(data, ENCODED_LINE_LENGTH / 2).map do |this_chunk|
|
131
|
+
'*' + this_chunk.unpack('H*').first + "\n"
|
132
|
+
end.join
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
|
2
|
+
require 'darcs/patchwriter'
|
3
|
+
|
4
|
+
module Darcs
|
5
|
+
|
6
|
+
class Repository
|
7
|
+
|
8
|
+
attr_reader :path
|
9
|
+
|
10
|
+
def initialize(path)
|
11
|
+
@path = path
|
12
|
+
@prefs_regexps = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
# Finds the repository we are in. Returns nil if we are not in a
|
16
|
+
# repository
|
17
|
+
def self.find
|
18
|
+
path = Dir.getwd
|
19
|
+
while !repository?(path)
|
20
|
+
return nil if File.dirname(path) == path
|
21
|
+
path = File.dirname(path)
|
22
|
+
end
|
23
|
+
self.new(path)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Determines whether the specified path is a repository
|
27
|
+
def self.repository?(path)
|
28
|
+
FileTest.directory?(File.join(path, '_darcs', 'patches')) &&
|
29
|
+
FileTest.exists?(File.join(path, '_darcs', 'inventory'))
|
30
|
+
end
|
31
|
+
|
32
|
+
def patches
|
33
|
+
if @patches.nil?
|
34
|
+
@patches = []
|
35
|
+
pi = nil
|
36
|
+
File.open(inventory_file, 'r') do |f|
|
37
|
+
@patches << Patch.new(self, pi) while pi = PatchInfo.read(f)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
@patches
|
41
|
+
end
|
42
|
+
|
43
|
+
def inventory_file
|
44
|
+
File.join(path, '_darcs', 'inventory')
|
45
|
+
end
|
46
|
+
|
47
|
+
# Determines whether this file a binary file according to the patterns
|
48
|
+
# found in _darcs/prefs/binaries.
|
49
|
+
def binary?(name)
|
50
|
+
prefs_regexp_file_matches(name, 'binaries')
|
51
|
+
end
|
52
|
+
|
53
|
+
# Determines whether this file a boring file according to the patterns
|
54
|
+
# found in _darcs/prefs/boring.
|
55
|
+
def boring?(name)
|
56
|
+
prefs_regexp_file_matches(name, 'boring')
|
57
|
+
end
|
58
|
+
|
59
|
+
def write_patch(patch_info)
|
60
|
+
patch = Patch.new(self, patch_info)
|
61
|
+
patch.write do |writer|
|
62
|
+
yield writer
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
protected
|
67
|
+
def prefs_regexp_file_matches(str, filename)
|
68
|
+
prefs_regexp(filename).match(str)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Constructs a compound regular expression from the lines of a file in
|
72
|
+
# the 'prefs' directory which contains one expression per line, except
|
73
|
+
# for comment lines which start with '#'. The regular expression is
|
74
|
+
# cached so it is not recomputed every time.
|
75
|
+
def prefs_regexp(filename)
|
76
|
+
if @prefs_regexps[filename].nil?
|
77
|
+
fpath = File.join(path, '_darcs', 'prefs', filename)
|
78
|
+
@prefs_regexps[filename] = Regexp.new('(' +
|
79
|
+
IO.readlines(fpath).delete_if {|l|
|
80
|
+
l[0..0] == '#'
|
81
|
+
}.map {|l|
|
82
|
+
(l[-1..-1] == "\n") ? l[0..-2] : l
|
83
|
+
}.join('|') + ')'
|
84
|
+
)
|
85
|
+
end
|
86
|
+
@prefs_regexps[filename]
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
# A Patch is the full representation of a patch file in a repository
|
92
|
+
# (PatchInfo is simply the inventory information).
|
93
|
+
#
|
94
|
+
# Patch acts as an aggregate of PatchInfo
|
95
|
+
class Patch
|
96
|
+
|
97
|
+
attr_accessor :repository, :info
|
98
|
+
|
99
|
+
def initialize(repository, info)
|
100
|
+
@repository = repository
|
101
|
+
@info = info
|
102
|
+
end
|
103
|
+
|
104
|
+
def method_missing(*args)
|
105
|
+
info.send(*args)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Retrieves the full path to the patch file
|
109
|
+
def filename
|
110
|
+
File.join(repository.path,'_darcs','patches',info.filename)
|
111
|
+
end
|
112
|
+
|
113
|
+
def write
|
114
|
+
patch_writer = PatchWriter.new(self)
|
115
|
+
begin
|
116
|
+
yield patch_writer
|
117
|
+
patch_writer.finish
|
118
|
+
File.open(repository.inventory_file, 'a') do |inv|
|
119
|
+
inv.write(info.to_s + "\n")
|
120
|
+
end
|
121
|
+
rescue
|
122
|
+
patch_writer.abort
|
123
|
+
raise $!
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
require 'test/unit'
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class DarcsImportTestCase < Test::Unit::TestCase
|
6
|
+
|
7
|
+
include TestHelper
|
8
|
+
|
9
|
+
def test_import
|
10
|
+
exe = File.join(File.dirname(File.dirname(File.expand_path(__FILE__))),
|
11
|
+
'bin', 'darcs-import')
|
12
|
+
|
13
|
+
TestDir.with do |td|
|
14
|
+
td.play <<EOF
|
15
|
+
echo "Hello, World" >test.gif
|
16
|
+
mkdir foo
|
17
|
+
printf 'no newline' >foo/bar.txt
|
18
|
+
printf 'two newlines at end\\n\\n' >foo/bar2.txt
|
19
|
+
printf '\\n' >foo/bar3.txt
|
20
|
+
mkdir foo/bar
|
21
|
+
mkdir baz
|
22
|
+
echo "File 2">baz/slime.txt
|
23
|
+
EMAIL='Joe Fabetes <joe@example.com>' ruby #{exe} 2>&1
|
24
|
+
darcs check
|
25
|
+
EOF
|
26
|
+
assert(/No changes/.match(`darcs whatsnew -s`),
|
27
|
+
"Changes found!")
|
28
|
+
output = `darcs changes -s`
|
29
|
+
assert(/A \.\/test\.gif/.match(output))
|
30
|
+
assert(/A \.\/foo\//.match(output))
|
31
|
+
assert(/A \.\/foo\/bar\.txt/.match(output))
|
32
|
+
assert(/A \.\/foo\/bar\//.match(output))
|
33
|
+
assert(/A \.\/baz\//.match(output))
|
34
|
+
assert(/A \.\/baz\/slime\.txt/.match(output))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
|
2
|
+
require 'darcs/patchinfo'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
class PatchInfoTestCase < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def test_initialize
|
8
|
+
pi = Darcs::PatchInfo.new('20051220115522', 'Test patch',
|
9
|
+
'Joe Fabetes <joe@example.com>')
|
10
|
+
|
11
|
+
assert_kind_of Darcs::PatchInfo, pi
|
12
|
+
assert_equal 'Test patch', pi.name
|
13
|
+
assert_equal 'Joe Fabetes <joe@example.com>', pi.author
|
14
|
+
assert !pi.inverted?
|
15
|
+
|
16
|
+
assert_kind_of Time, pi.date
|
17
|
+
assert_equal 2005, pi.date.year
|
18
|
+
assert_equal 12, pi.date.month
|
19
|
+
assert_equal 20, pi.date.day
|
20
|
+
assert_equal 11, pi.date.hour
|
21
|
+
assert_equal 55, pi.date.min
|
22
|
+
assert_equal 22, pi.date.sec
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_filename
|
26
|
+
pi = Darcs::PatchInfo.new('20051220170424', 'Rakefile, directories',
|
27
|
+
'Jason M. Felice <jfelice@cronosys.com>')
|
28
|
+
assert_equal '20051220170424-e0cd7-00d5859bbcf77c9b726e7c4fd6fb8a536cd3cfcd.gz', pi.filename
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_to_s
|
32
|
+
pi = Darcs::PatchInfo.new('20051220170424', 'Rakefile, directories',
|
33
|
+
'Jason M. Felice <jfelice@cronosys.com>')
|
34
|
+
assert_equal "[Rakefile, directories\nJason M. Felice <jfelice@cronosys.com>**20051220170424]", pi.to_s
|
35
|
+
|
36
|
+
pi = Darcs::PatchInfo.new('20051220170424', 'Rakefile, directories',
|
37
|
+
'Jason M. Felice <jfelice@cronosys.com>',
|
38
|
+
"And here is
|
39
|
+
a test log
|
40
|
+
message."
|
41
|
+
)
|
42
|
+
|
43
|
+
expect = "[Rakefile, directories
|
44
|
+
Jason M. Felice <jfelice@cronosys.com>**20051220170424
|
45
|
+
And here is
|
46
|
+
a test log
|
47
|
+
message.
|
48
|
+
]"
|
49
|
+
assert_equal expect, pi.to_s
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
@@ -0,0 +1,86 @@
|
|
1
|
+
|
2
|
+
require 'darcs/patchinfo'
|
3
|
+
require 'darcs/repository'
|
4
|
+
require 'darcs/patchwriter'
|
5
|
+
require 'test/unit'
|
6
|
+
require 'test_helper'
|
7
|
+
|
8
|
+
# Make some things accessible so we can unit test them
|
9
|
+
module Darcs
|
10
|
+
module Chunk
|
11
|
+
class Binary
|
12
|
+
def public_chunk(*args); chunk(*args); end
|
13
|
+
def public_hex_encode(*args); hex_encode(*args); end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class PatchWriterTestCase < Test::Unit::TestCase
|
19
|
+
|
20
|
+
include TestHelper
|
21
|
+
|
22
|
+
def test_new
|
23
|
+
TestDir.with do |td|
|
24
|
+
td.play <<EOF
|
25
|
+
darcs initialize
|
26
|
+
mkdir foo_dir
|
27
|
+
echo "Hello, World!"> foo_file
|
28
|
+
echo "Hello, World!"> bar_file
|
29
|
+
EOF
|
30
|
+
|
31
|
+
repo = Darcs::Repository.new(td.path)
|
32
|
+
patch_info = Darcs::PatchInfo.new(Time.now, 'Test Patch',
|
33
|
+
'joe@example.com')
|
34
|
+
repo.write_patch(patch_info) do |writer|
|
35
|
+
|
36
|
+
assert_kind_of Darcs::PatchWriter, writer
|
37
|
+
assert_kind_of Darcs::Patch, writer.patch
|
38
|
+
assert_equal patch_info, writer.patch.info
|
39
|
+
|
40
|
+
writer << Darcs::Chunk::AddDirectory.new('./foo_dir')
|
41
|
+
writer << Darcs::Chunk::AddFile.new('./foo_file')
|
42
|
+
writer << Darcs::Chunk::Hunk.new('./foo_file', 1, "+Hello, World!\n")
|
43
|
+
writer << Darcs::Chunk::AddFile.new('./bar_file')
|
44
|
+
writer << Darcs::Chunk::Binary.new('./bar_file', "", "Hello, World!\n")
|
45
|
+
end
|
46
|
+
|
47
|
+
# We just recorded a patch, we didn't apply it, so...
|
48
|
+
td.play <<EOF
|
49
|
+
mkdir _darcs/current/foo_dir
|
50
|
+
echo 'Hello, World!'> _darcs/current/foo_file
|
51
|
+
echo 'Hello, World!'> _darcs/current/bar_file
|
52
|
+
EOF
|
53
|
+
|
54
|
+
plist = repo.patches
|
55
|
+
assert_equal 1, plist.size
|
56
|
+
assert_equal 'Test Patch', plist[0].name
|
57
|
+
assert_equal 'joe@example.com', plist[0].author
|
58
|
+
assert FileTest.exists?(plist[0].filename)
|
59
|
+
|
60
|
+
# Check repo consistency
|
61
|
+
td.play "darcs check"
|
62
|
+
|
63
|
+
# Verify that darcs can read it
|
64
|
+
output = `darcs changes -s`
|
65
|
+
assert(/ joe@example.com\n \* Test Patch\n$/.match(output))
|
66
|
+
assert(/A \.\/foo_dir\//.match(output))
|
67
|
+
assert(/A \.\/foo_file/.match(output))
|
68
|
+
assert(/A \.\/bar_file/.match(output))
|
69
|
+
|
70
|
+
output = `darcs whatsnew`
|
71
|
+
assert(/No changes/.match(output),
|
72
|
+
"darcs is seeing changes!:\n#{output}")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_binary_hex_encode
|
77
|
+
binary_chunk = Darcs::Chunk::Binary.new('foo', '', 'baz')
|
78
|
+
|
79
|
+
assert_equal [ '1234567890', '12345' ],
|
80
|
+
binary_chunk.public_chunk('123456789012345', 10)
|
81
|
+
|
82
|
+
assert_equal "*313233343536373839\n",
|
83
|
+
binary_chunk.public_hex_encode('123456789')
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
|
2
|
+
require 'test/unit'
|
3
|
+
require 'darcs/repository'
|
4
|
+
require 'darcs/patchinfo'
|
5
|
+
require 'find'
|
6
|
+
require 'test_helper'
|
7
|
+
require 'tempfile'
|
8
|
+
|
9
|
+
class RepostioryTestCase < Test::Unit::TestCase
|
10
|
+
|
11
|
+
include TestHelper
|
12
|
+
|
13
|
+
def test_create
|
14
|
+
repo = Darcs::Repository.new('/tmp')
|
15
|
+
assert_kind_of Darcs::Repository, repo
|
16
|
+
assert_equal '/tmp', repo.path
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_patches
|
20
|
+
TestDir.with do |td|
|
21
|
+
tf = Tempfile.new('test')
|
22
|
+
File.open(tf.path, 'w') do |f|
|
23
|
+
f.write("Test patch 3\nHere is log line 1\nHere is log line 2\nend\n")
|
24
|
+
end
|
25
|
+
td.play <<EOF
|
26
|
+
darcs initialize
|
27
|
+
echo 'this is foo' >> foo.txt
|
28
|
+
darcs add foo.txt
|
29
|
+
darcs record -a -A 'Joe Fabetes <joe@example.com>' -m 'Test patch 1'
|
30
|
+
echo 'hi' >> bar.txt
|
31
|
+
darcs add bar.txt
|
32
|
+
darcs record -a -A 'Joe Fabetes <joe@example.com>' -m 'Test patch 2'
|
33
|
+
echo 'bazfile' >> baz.txt
|
34
|
+
darcs add baz.txt
|
35
|
+
darcs record -a -A 'Joe Fabetes <joe@example.com>' --logfile #{tf.path}
|
36
|
+
EOF
|
37
|
+
repo = Darcs::Repository.new(td.path)
|
38
|
+
patches = repo.patches
|
39
|
+
|
40
|
+
assert_equal 3, patches.size
|
41
|
+
patches.each do |patch|
|
42
|
+
assert_kind_of Darcs::Patch, patch
|
43
|
+
assert_equal 'Joe Fabetes <joe@example.com>', patch.author
|
44
|
+
assert FileTest.exists?(patch.filename),
|
45
|
+
"patch.filename isn't valid."
|
46
|
+
end
|
47
|
+
assert_equal "Test patch 3", patches[2].name
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_repository?
|
52
|
+
TestDir.with do |td|
|
53
|
+
td.play "darcs initialize"
|
54
|
+
|
55
|
+
assert Darcs::Repository.repository?(td.path)
|
56
|
+
assert !Darcs::Repository.repository?('/tmp')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_find
|
61
|
+
TestDir.with do |td|
|
62
|
+
td.play "darcs initialize"
|
63
|
+
|
64
|
+
repo = Darcs::Repository.find
|
65
|
+
assert_kind_of Darcs::Repository, repo
|
66
|
+
assert_equal td.path, repo.path
|
67
|
+
|
68
|
+
Dir.mkdir('foo')
|
69
|
+
td.play "darcs add foo"
|
70
|
+
Dir.chdir('foo')
|
71
|
+
|
72
|
+
repo = Darcs::Repository.find
|
73
|
+
assert_kind_of Darcs::Repository, repo
|
74
|
+
assert_equal td.path, repo.path
|
75
|
+
|
76
|
+
Dir.chdir('/tmp')
|
77
|
+
repo = Darcs::Repository.find
|
78
|
+
assert_equal nil, repo
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_boring_and_binary
|
83
|
+
TestDir.with do |td|
|
84
|
+
td.play "darcs initialize"
|
85
|
+
|
86
|
+
repo = Darcs::Repository.find
|
87
|
+
|
88
|
+
assert repo.boring?('./foo/CVS/Shucks'), "CVS files are not boring!"
|
89
|
+
assert repo.binary?('./foo.jpg'), "JPEG files are not binary!"
|
90
|
+
assert !repo.boring?('./foo.c'), "C files are boring?!"
|
91
|
+
assert !repo.binary?('./foo.pl'), "Perl files are binary? (Well, close..)"
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
|
2
|
+
module TestHelper
|
3
|
+
|
4
|
+
# Utility class for tests to work with a temporary directory, play commands
|
5
|
+
# in it, automatically clean up files, etc.
|
6
|
+
#
|
7
|
+
# Use like so:
|
8
|
+
#
|
9
|
+
# TestHelper::TestDir.with do |td|
|
10
|
+
# td.play <<EOF
|
11
|
+
# echo hi >>foo.txt
|
12
|
+
# touch bar.txt
|
13
|
+
# EOF
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
class TestDir
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@path = "/tmp/rdarcs_#{$$}_#{rand(100000)}"
|
20
|
+
Dir.mkdir(@path)
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :path
|
24
|
+
|
25
|
+
def in
|
26
|
+
old_path = Dir.getwd
|
27
|
+
Dir.chdir(path)
|
28
|
+
begin
|
29
|
+
yield
|
30
|
+
ensure
|
31
|
+
Dir.chdir(old_path)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Retrieves this temporary directory's path
|
36
|
+
def play (script)
|
37
|
+
script.split(/\n/).each do |cmd|
|
38
|
+
output = `#{cmd}`
|
39
|
+
raise "#{cmd} -> #{output} (error_code = #{$?})" if $? != 0
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Removes the directory and all files and sub-directories in it
|
44
|
+
def delete
|
45
|
+
directories = []
|
46
|
+
Find.find(path) do |ent|
|
47
|
+
if FileTest.directory?(ent)
|
48
|
+
directories << ent
|
49
|
+
else
|
50
|
+
File.unlink(ent)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
directories.sort{|a, b| b.size <=> a.size}.each do |dir|
|
54
|
+
Dir.rmdir(dir)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Creates a new temporary directory, runs a block of code in it, and
|
59
|
+
# cleans up afterward.
|
60
|
+
def self.with
|
61
|
+
repo = self.new
|
62
|
+
begin
|
63
|
+
repo.in do
|
64
|
+
yield repo
|
65
|
+
end
|
66
|
+
ensure
|
67
|
+
repo.delete
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: darcs-ruby
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.0.1
|
7
|
+
date: 2005-12-22 00:00:00 -05:00
|
8
|
+
summary: Interface to Darcs change control system
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: jfelice@cronosys.com
|
12
|
+
homepage: http://eraserhead.net/darcs/darcs-ruby/doc/
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
-
|
22
|
+
- ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.0
|
25
|
+
version:
|
26
|
+
platform: ruby
|
27
|
+
signing_key:
|
28
|
+
cert_chain:
|
29
|
+
authors:
|
30
|
+
- Jason M. Felice
|
31
|
+
files:
|
32
|
+
- lib/darcs
|
33
|
+
- lib/darcs/repository.rb
|
34
|
+
- lib/darcs/patchinfo.rb
|
35
|
+
- lib/darcs/patchwriter.rb
|
36
|
+
- test/test_helper.rb
|
37
|
+
- test/patchwriter_test.rb
|
38
|
+
- test/repository_test.rb
|
39
|
+
- test/patchinfo_test.rb
|
40
|
+
- test/darcs-import_test.rb
|
41
|
+
- Rakefile
|
42
|
+
- bin/darcs-import
|
43
|
+
test_files:
|
44
|
+
- test/patchwriter_test.rb
|
45
|
+
- test/repository_test.rb
|
46
|
+
- test/patchinfo_test.rb
|
47
|
+
- test/darcs-import_test.rb
|
48
|
+
rdoc_options: []
|
49
|
+
extra_rdoc_files: []
|
50
|
+
executables:
|
51
|
+
- darcs-import
|
52
|
+
extensions: []
|
53
|
+
requirements: []
|
54
|
+
dependencies: []
|