darcs-ruby 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|