rjgit 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +3 -3
- data/README.md +41 -10
- data/lib/actor.rb +12 -9
- data/lib/blob.rb +19 -8
- data/lib/commit.rb +32 -7
- data/lib/config.rb +1 -1
- data/lib/git.rb +5 -5
- data/lib/java/jars/org.eclipse.jgit-3.1.0.201310021548-r.jar +0 -0
- data/lib/repo.rb +60 -7
- data/lib/rjgit.rb +194 -7
- data/lib/rjgit_helpers.rb +49 -2
- data/lib/tag.rb +8 -1
- data/lib/tree.rb +51 -7
- data/lib/version.rb +1 -1
- metadata +6 -13
- data/lib/java/jars/org.eclipse.jgit-3.0.0.201306101825-r.jar +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f9e630be01944c941f17a49c0672e3b4e6152d5b
|
4
|
+
data.tar.gz: 83a4b49462dcb91f3752f6efd78e3f07365472e5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d993640e4a08b325bda42aef04ccaf2eca55afd5b1ac47d8553398c343db871635a0216f6543da639a1ddb60f373a1c87df7ea928ab4b672f8c6f5937802d965
|
7
|
+
data.tar.gz: c75fe41b10fb0b21cd4d48944d981bace59aa130455e3468e92d9426edc0b54a0e0f6f006748cc2add6cc3ddb0829bdacf32669e63b08a95e0ed80a03999ac1b
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -5,6 +5,7 @@ RJGit
|
|
5
5
|
|
6
6
|
[![Build Status](https://travis-ci.org/repotag/rjgit.png)](https://travis-ci.org/repotag/rjgit)
|
7
7
|
[![Coverage Status](https://coveralls.io/repos/repotag/rjgit/badge.png?branch=master)](https://coveralls.io/r/repotag/rjgit)
|
8
|
+
[![Gem Version](https://badge.fury.io/rb/rjgit.png)](http://badge.fury.io/rb/rjgit)
|
8
9
|
|
9
10
|
Authors
|
10
11
|
-------
|
@@ -37,7 +38,9 @@ $ gem install rjgit
|
|
37
38
|
|
38
39
|
Usage
|
39
40
|
-----
|
40
|
-
RJGit wraps most (if not all) of JGit's core functionality;
|
41
|
+
RJGit wraps most (if not all) of JGit's core functionality; it has classes for all important Git objects, i.e., Repo, Blob, Tree, Commit, and Tag. It allows parsing and manipulation of these objects in an intuitive manner, either simulating ordinary git usage (with a working directory on disk) or on a lower level, through creating new git objects manually (also works with 'bare' repositories, without a working directory).
|
42
|
+
|
43
|
+
See below for some examples of what you can do with RJGit. Make sure you have [JRuby](http://jruby.org/) installed.
|
41
44
|
|
42
45
|
### Require the gem and include the RJGit module
|
43
46
|
|
@@ -56,33 +59,53 @@ repo = Repo.new("repo.git")
|
|
56
59
|
|
57
60
|
```ruby
|
58
61
|
repo = Repo.new("repo.git", :create => true)
|
59
|
-
repo = Repo.new("repo.git", :create => true, :
|
62
|
+
repo = Repo.new("repo.git", :create => true, :is_bare => true) # Create a 'bare' git repo.
|
63
|
+
repo.bare? # Is this a bare repository?
|
60
64
|
```
|
61
65
|
|
62
|
-
### Getting
|
66
|
+
### Getting commits
|
63
67
|
```ruby
|
64
68
|
repo.commits('master')
|
65
69
|
repo.commits('959329025f67539fb82e76b02782322fad032821')
|
70
|
+
commit = repo.commits('master').first # a Commit object; try commit.actor, commit.id, etc.
|
66
71
|
# Similarly for getting tags, branches, trees (directories), and blobs (files).
|
67
72
|
```
|
68
73
|
|
74
|
+
### Finding a single object by SHA
|
75
|
+
```ruby
|
76
|
+
repo.find('959329025f67539fb82e76b02782322fad032821')
|
77
|
+
repo.find('959329025f67539fb82e76b02782322fad032821', :commit) # Find a specific :commit, :blob, :tree, or :tag
|
78
|
+
```
|
79
|
+
|
69
80
|
### Getting tags
|
70
81
|
```ruby
|
71
82
|
tag = repo.tags['example_tag']
|
72
83
|
tag.id # tag's object id
|
73
84
|
tag.author.name # Etcetera
|
85
|
+
some_object = Porcelain.object_for_tag(repo, tag) # Returns the tagged object; e.g. a Commit
|
86
|
+
```
|
87
|
+
|
88
|
+
### Blobs and Trees
|
89
|
+
```ruby
|
90
|
+
blob = repo.blob("example/file.txt") # Retrieve a file by filepath...
|
91
|
+
blob = repo.find("959329025f67539fb82e76b02782322fad032822", :blob) # ...or by SHA
|
92
|
+
blob.data # Cat the file; also blob.id, blob.mode, etc.
|
93
|
+
tree = repo.tree("example") # Retrieve a tree by filepath...
|
94
|
+
tree = repo.find("959329025f67539fb82e76b02782322fad032000", :tree) #...or by SHA
|
95
|
+
tree.data # List the tree's contents (blobs and trees). Also tree.id, tree.mode, etc.
|
96
|
+
tree.each {|entry| puts entry.inspect} # Loop over the Tree's children (Blobs and Trees)
|
97
|
+
tree.trees # An array of the Tree's child Trees
|
98
|
+
tree.blobs # An array of the Tree's child Blobs
|
99
|
+
Porcelain::ls_tree(repo, repo.tree("example"), :print => true, :recursive => true, :branch => 'mybranch') # Outputs the Tree's contents to $stdout. Faster for recursive listing than Tree#each. Passing nil as the second argument lists the entire repository. Branch defaults to HEAD.
|
74
100
|
```
|
75
101
|
|
76
|
-
###
|
102
|
+
### Creating blobs and trees from scratch
|
77
103
|
```ruby
|
78
|
-
|
79
|
-
|
80
|
-
repo.tree("example") # Retrieve a tree by filepath
|
81
|
-
repo.tree("example").data # List the tree's contents (blobs and trees)
|
82
|
-
Porcelain::ls_tree(repo, repo.tree("example"), :print => true, :recursive => true, :branch => 'mybranch') # Outputs a file list to $stdout. Passing nil as the second argument lists the entire repository. Branch defaults to HEAD.
|
104
|
+
blob = Blob.new_from_string(repo, "Contents of the new blob.") # Inserts the blob into the repository, returns an RJGit::Blob
|
105
|
+
tree = Tree.new_from_hashmap(repo, {"newblob" => "contents", "newtree" => { "otherblob" => "this blob is contained in the tree 'newtree'" } } ) # Constructs the tree and its children based on the hashmap and inserts it into the repository, returning an RJGit::Tree. Tree.new_from_hashmap takes an RJGit::Tree as an optional third argument, in which case the new tree will consist of the children of that Tree *plus* the contents of the hashmap.
|
83
106
|
```
|
84
107
|
|
85
|
-
###
|
108
|
+
### Committing and adding branches to repositories, 'porcelain' style (only works with non-bare repos)
|
86
109
|
```ruby
|
87
110
|
repo.create_branch('new_branch') # Similarly for deleting, renaming
|
88
111
|
repo.checkout('new_branch')
|
@@ -90,6 +113,14 @@ repo.add('new_file.txt') # Similarly for removing
|
|
90
113
|
repo.commit('My message')
|
91
114
|
```
|
92
115
|
|
116
|
+
### Committing and adding branches to repositories, 'plumbing' style (also works with bare repos)
|
117
|
+
```ruby
|
118
|
+
repo = repo.new("repo.git")
|
119
|
+
tree = Tree.new_from_hashmap(repo, {"newblob" => "contents"}, repo.head.tree ) # As above, use the current head commit's tree as a starting point and add "newblob"
|
120
|
+
actor = RJGit::Actor.new("test", "test@repotag.org")
|
121
|
+
commit = Commit.new_with_tree(repo, tree, "My commit message", actor) # Create a new commit with tree as base tree
|
122
|
+
```
|
123
|
+
|
93
124
|
### And more...
|
94
125
|
```ruby
|
95
126
|
pack = RJGitReceivePack.new(repo) # Implement the smart-http protocol with RJGitReceivePack and RJGitUploadPack
|
data/lib/actor.rb
CHANGED
@@ -9,15 +9,18 @@ module RJGit
|
|
9
9
|
|
10
10
|
RJGit.delegate_to(PersonIdent, :@person_ident)
|
11
11
|
|
12
|
-
def self.new_from_name_and_email(name, email)
|
13
|
-
return self.new(PersonIdent.new(name, email))
|
14
|
-
end
|
15
12
|
alias_method :to_s, :name
|
16
|
-
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
13
|
+
|
14
|
+
def self.new_from_person_ident(person_ident)
|
15
|
+
name = person_ident.get_name
|
16
|
+
email = person_ident.get_email_address
|
17
|
+
return self.new(name, email)
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(name, email)
|
21
|
+
@name = name
|
22
|
+
@email = email
|
23
|
+
@person_ident = PersonIdent.new(name, email)
|
21
24
|
end
|
22
25
|
|
23
26
|
# Create an Actor from a string.
|
@@ -28,7 +31,7 @@ module RJGit
|
|
28
31
|
def self.from_string(str)
|
29
32
|
if str =~ /<.+>/
|
30
33
|
m, name, email = *str.match(/(.*) <(.+?)>/)
|
31
|
-
return self.
|
34
|
+
return self.new(name, email)
|
32
35
|
end
|
33
36
|
end
|
34
37
|
|
data/lib/blob.rb
CHANGED
@@ -7,11 +7,11 @@ module RJGit
|
|
7
7
|
attr_reader :id, :mode, :name, :path, :jblob
|
8
8
|
RJGit.delegate_to(RevBlob, :@jblob)
|
9
9
|
|
10
|
-
def initialize(
|
11
|
-
@jrepo =
|
10
|
+
def initialize(repository, mode, path, jblob)
|
11
|
+
@jrepo = RJGit.repository_type(repository)
|
12
12
|
@jblob = jblob
|
13
13
|
@path = path
|
14
|
-
@name = File.basename(path)
|
14
|
+
@name = @path ? File.basename(@path) : nil
|
15
15
|
@mode = mode
|
16
16
|
@id = ObjectId.toString(jblob.get_id)
|
17
17
|
end
|
@@ -36,7 +36,11 @@ module RJGit
|
|
36
36
|
def data
|
37
37
|
@data ||= RJGit::Porcelain.cat_file(@jrepo, @jblob)
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
|
+
def is_symlink?
|
41
|
+
@mode == SYMLINK_TYPE
|
42
|
+
end
|
43
|
+
|
40
44
|
# The mime type of this file (based on the filename)
|
41
45
|
# Returns String
|
42
46
|
def mime_type
|
@@ -48,10 +52,17 @@ module RJGit
|
|
48
52
|
guesses.first ? guesses.first.simplified : DEFAULT_MIME_TYPE
|
49
53
|
end
|
50
54
|
|
55
|
+
def self.new_from_string(repository, contents)
|
56
|
+
repository = RJGit.repository_type(repository)
|
57
|
+
blob_id = RJGit::Plumbing::TreeBuilder.new(repository).write_blob(contents, true)
|
58
|
+
walk = RevWalk.new(repository)
|
59
|
+
Blob.new(repository, FileMode::REGULAR_FILE, nil, walk.lookup_blob(blob_id))
|
60
|
+
end
|
61
|
+
|
51
62
|
# Finds a particular Blob in repository matching file_path
|
52
|
-
def self.find_blob(repository, file_path,
|
63
|
+
def self.find_blob(repository, file_path, revstring=Constants::HEAD)
|
53
64
|
jrepo = RJGit.repository_type(repository)
|
54
|
-
last_commit_hash = jrepo.resolve(
|
65
|
+
last_commit_hash = jrepo.resolve(revstring)
|
55
66
|
return nil if last_commit_hash.nil?
|
56
67
|
|
57
68
|
walk = RevWalk.new(jrepo)
|
@@ -64,8 +75,8 @@ module RJGit
|
|
64
75
|
if treewalk.next
|
65
76
|
jblob = walk.lookup_blob(treewalk.objectId(0))
|
66
77
|
if jblob
|
67
|
-
mode = RJGit.
|
68
|
-
Blob.new(jrepo,
|
78
|
+
mode = RJGit.get_file_mode_with_path(jrepo, file_path, jtree)
|
79
|
+
Blob.new(jrepo, mode, file_path, jblob)
|
69
80
|
end
|
70
81
|
else
|
71
82
|
nil
|
data/lib/commit.rb
CHANGED
@@ -14,23 +14,48 @@ module RJGit
|
|
14
14
|
attr_reader :message
|
15
15
|
attr_reader :short_message
|
16
16
|
attr_reader :jcommit
|
17
|
-
attr_reader :
|
17
|
+
attr_reader :parent_count
|
18
18
|
|
19
19
|
RJGit.delegate_to(RevCommit, :@jcommit)
|
20
20
|
|
21
|
-
def initialize(commit)
|
21
|
+
def initialize(repository, commit)
|
22
|
+
@jrepo = RJGit.repository_type(repository)
|
22
23
|
@jcommit = commit
|
23
24
|
@id = ObjectId.to_string(commit.get_id)
|
24
|
-
@actor = Actor.
|
25
|
-
@committer = Actor.
|
25
|
+
@actor = Actor.new_from_person_ident(@jcommit.get_author_ident)
|
26
|
+
@committer = Actor.new_from_person_ident(@jcommit.get_committer_ident)
|
26
27
|
@committed_date = Time.at(@jcommit.commit_time)
|
27
28
|
@message = @jcommit.get_full_message
|
28
29
|
@short_message = @jcommit.get_short_message
|
29
|
-
@
|
30
|
+
@parent_count = @jcommit.get_parent_count
|
31
|
+
end
|
32
|
+
|
33
|
+
def tree
|
34
|
+
@tree ||= Tree.new(@jrepo, FileMode::TREE, nil, @jcommit.get_tree)
|
30
35
|
end
|
31
36
|
|
32
37
|
def parents
|
33
|
-
@parents ||= @jcommit.get_parents.map{|parent| Commit.new(parent)
|
38
|
+
@parents ||= @jcommit.get_parents.map {|parent| Commit.new(@jrepo, parent)}
|
39
|
+
end
|
40
|
+
|
41
|
+
# Pass an empty array for parents if the commit should have no parents
|
42
|
+
def self.new_with_tree(repository, tree, message, actor, parents = nil)
|
43
|
+
repository = RJGit.repository_type(repository)
|
44
|
+
parents = parents ? parents : repository.resolve("refs/heads/#{Constants::MASTER}")
|
45
|
+
new_commit = RJGit::Plumbing::Index.new(repository).do_commit(message, actor, parents, tree)
|
46
|
+
Commit.new(repository, RevWalk.new(repository).parseCommit(new_commit))
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.find_head(repository)
|
50
|
+
repository = RJGit.repository_type(repository)
|
51
|
+
return nil if repository.nil?
|
52
|
+
begin
|
53
|
+
walk = RevWalk.new(repository)
|
54
|
+
objhead = repository.resolve(Constants::HEAD)
|
55
|
+
return Commit.new(repository, walk.parseCommit(objhead))
|
56
|
+
rescue NativeException => e
|
57
|
+
return nil
|
58
|
+
end
|
34
59
|
end
|
35
60
|
|
36
61
|
def self.find_all(repository, ref, options)
|
@@ -41,7 +66,7 @@ module RJGit
|
|
41
66
|
objhead = repository.resolve(ref)
|
42
67
|
root = walk.parse_commit(objhead)
|
43
68
|
walk.mark_start(root)
|
44
|
-
commits = walk.map { |commit| Commit.new(commit) }
|
69
|
+
commits = walk.map { |commit| Commit.new(repository, commit) }
|
45
70
|
return commits.first(options[:limit])
|
46
71
|
rescue NativeException => e
|
47
72
|
return Array.new
|
data/lib/config.rb
CHANGED
data/lib/git.rb
CHANGED
@@ -27,7 +27,7 @@ module RJGit
|
|
27
27
|
logs = @jgit.log
|
28
28
|
commits = Array.new
|
29
29
|
logs.call.each do |jcommit|
|
30
|
-
commits << Commit.new(jcommit)
|
30
|
+
commits << Commit.new(jrepo, jcommit)
|
31
31
|
end
|
32
32
|
commits
|
33
33
|
end
|
@@ -42,7 +42,7 @@ module RJGit
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def commit(message)
|
45
|
-
Commit.new(@jgit.commit.set_message(message).call)
|
45
|
+
Commit.new(jrepo, @jgit.commit.set_message(message).call)
|
46
46
|
end
|
47
47
|
|
48
48
|
def clone(remote, local, options = {})
|
@@ -53,7 +53,7 @@ module RJGit
|
|
53
53
|
clone_command = Git.clone_repository
|
54
54
|
clone_command.setURI(remote)
|
55
55
|
clone_command.set_directory(java.io.File.new(local))
|
56
|
-
clone_command.set_bare(true) if options[:
|
56
|
+
clone_command.set_bare(true) if options[:is_bare]
|
57
57
|
if options[:branch]
|
58
58
|
if options[:branch] == :all
|
59
59
|
clone_command.set_clone_all_branches(true)
|
@@ -92,7 +92,7 @@ module RJGit
|
|
92
92
|
tag_command.set_name(name)
|
93
93
|
tag_command.set_force_update(force)
|
94
94
|
tag_command.set_message(message)
|
95
|
-
tag_command.set_object_id(commit_or_revision) if commit_or_revision
|
95
|
+
tag_command.set_object_id(RJGit.commit_type(commit_or_revision)) if commit_or_revision
|
96
96
|
if actor
|
97
97
|
actor = RJGit.actor_type(actor)
|
98
98
|
tag_command.set_tagger(actor)
|
@@ -182,7 +182,7 @@ module RJGit
|
|
182
182
|
commits.each do |commit|
|
183
183
|
revert_command.include commit.jcommit
|
184
184
|
end
|
185
|
-
Commit.new(revert_command.call)
|
185
|
+
Commit.new(jrepo, revert_command.call)
|
186
186
|
end
|
187
187
|
|
188
188
|
def status
|
Binary file
|
data/lib/repo.rb
CHANGED
@@ -49,13 +49,13 @@ module RJGit
|
|
49
49
|
# If the repo path is new
|
50
50
|
unless File.exists?(epath)
|
51
51
|
# take user setting if defined
|
52
|
-
bare = !! options[:
|
52
|
+
bare = !! options[:is_bare] unless options[:is_bare].nil?
|
53
53
|
# If the repo path exists
|
54
54
|
else
|
55
55
|
# scan the directory for a .git directory
|
56
56
|
bare = File.exists?(gitpath) ? false : true
|
57
57
|
# but allow overriding user setting
|
58
|
-
bare = !! options[:
|
58
|
+
bare = !! options[:is_bare] unless options[:is_bare].nil?
|
59
59
|
end
|
60
60
|
|
61
61
|
@path = bare ? epath : gitpath
|
@@ -69,8 +69,9 @@ module RJGit
|
|
69
69
|
def bare?
|
70
70
|
@jrepo.is_bare
|
71
71
|
end
|
72
|
+
alias_method :bare, :bare?
|
72
73
|
|
73
|
-
def self.create(path, options = {:
|
74
|
+
def self.create(path, options = {:is_bare => false})
|
74
75
|
options[:create] = true
|
75
76
|
Repo.new(path, options)
|
76
77
|
end
|
@@ -79,11 +80,20 @@ module RJGit
|
|
79
80
|
@jrepo.create(self.bare?)
|
80
81
|
end
|
81
82
|
|
83
|
+
def self.new_from_jgit_repo(jrepo)
|
84
|
+
path = File.dirname(jrepo.get_directory.get_path)
|
85
|
+
Repo.new(path, {:is_bare => jrepo.is_bare})
|
86
|
+
end
|
87
|
+
|
82
88
|
def commits(ref="master", limit=100)
|
83
89
|
options = { :limit => limit }
|
84
90
|
Commit.find_all(@jrepo, ref, options)
|
85
91
|
end
|
86
92
|
|
93
|
+
def head
|
94
|
+
Commit.find_head(@jrepo)
|
95
|
+
end
|
96
|
+
|
87
97
|
def valid?
|
88
98
|
@jrepo.get_object_database.exists
|
89
99
|
end
|
@@ -152,15 +162,58 @@ module RJGit
|
|
152
162
|
def clean(options = {})
|
153
163
|
@git.clean(options)
|
154
164
|
end
|
165
|
+
|
166
|
+
def find(sha, type = :any)
|
167
|
+
begin
|
168
|
+
oi = ObjectId.from_string(sha)
|
169
|
+
walk = RevWalk.new(@jrepo)
|
170
|
+
rev_object = case type
|
171
|
+
when :any
|
172
|
+
walk.parse_any(oi)
|
173
|
+
when :tree
|
174
|
+
walk.parse_tree(oi)
|
175
|
+
when :blob
|
176
|
+
walk.parse_any(oi)
|
177
|
+
when :tag
|
178
|
+
walk.parse_tag(oi)
|
179
|
+
when :commit
|
180
|
+
walk.parse_commit(oi)
|
181
|
+
else nil
|
182
|
+
end
|
183
|
+
rescue Java::OrgEclipseJgitErrors::MissingObjectException, Java::JavaLang::IllegalArgumentException, Java::JavaLang::NullPointerException
|
184
|
+
return nil
|
185
|
+
end
|
186
|
+
return nil if rev_object.nil?
|
187
|
+
object_type = (type == :any || type == :blob) ? RJGit.sym_for_type(rev_object.get_type) : type
|
188
|
+
return nil if type == :blob && object_type != :blob # Blobs need to be found with parse_any, so make sure that the result of this is actually a blob.
|
189
|
+
return case object_type
|
190
|
+
when :tree
|
191
|
+
Tree.new(@jrepo, nil, nil, rev_object)
|
192
|
+
when :blob
|
193
|
+
mode = RJGit.get_file_mode(@jrepo, rev_object)
|
194
|
+
Blob.new(@jrepo, mode, nil, rev_object)
|
195
|
+
when :tag
|
196
|
+
Tag.new(rev_object)
|
197
|
+
when :commit
|
198
|
+
Commit.new(jrepo, rev_object)
|
199
|
+
end
|
200
|
+
end
|
155
201
|
|
156
202
|
# Convenience method to retrieve a Blob by name
|
157
|
-
def blob(file_path)
|
158
|
-
Blob.find_blob(@jrepo, file_path)
|
203
|
+
def blob(file_path, revstring=Constants::HEAD)
|
204
|
+
Blob.find_blob(@jrepo, file_path, revstring)
|
159
205
|
end
|
160
206
|
|
161
207
|
# Convenience method to retrieve a Tree by name
|
162
|
-
def tree(file_path)
|
163
|
-
Tree.find_tree(@jrepo, file_path)
|
208
|
+
def tree(file_path, revstring=Constants::HEAD)
|
209
|
+
Tree.find_tree(@jrepo, file_path, revstring)
|
210
|
+
end
|
211
|
+
|
212
|
+
def update_ref(commit, force = false, ref = "refs/heads/#{Constants::MASTER}")
|
213
|
+
ref_updater = @jrepo.updateRef(ref)
|
214
|
+
ref_updater.setNewObjectId(RJGit.commit_type(commit))
|
215
|
+
msg = force ? :update : :forceUpdate
|
216
|
+
ref_updater.send(msg).to_string
|
164
217
|
end
|
165
218
|
|
166
219
|
# Update the info files required for fetching files over the dump-HTTP protocol
|
data/lib/rjgit.rb
CHANGED
@@ -25,7 +25,7 @@ module RJGit
|
|
25
25
|
|
26
26
|
import 'org.eclipse.jgit.lib.ObjectId'
|
27
27
|
|
28
|
-
|
28
|
+
module Porcelain
|
29
29
|
|
30
30
|
import 'org.eclipse.jgit.api.AddCommand'
|
31
31
|
import 'org.eclipse.jgit.api.CommitCommand'
|
@@ -42,9 +42,23 @@ module RJGit
|
|
42
42
|
repository.commit(message)
|
43
43
|
end
|
44
44
|
|
45
|
+
def self.object_for_tag(repository, tag)
|
46
|
+
repository.find(tag.object.name, RJGit.sym_for_type(tag.object_type))
|
47
|
+
end
|
48
|
+
|
45
49
|
# http://dev.eclipse.org/mhonarc/lists/jgit-dev/msg00558.html
|
46
|
-
def self.cat_file(repository,
|
47
|
-
|
50
|
+
def self.cat_file(repository, blob)
|
51
|
+
jrepo = RJGit.repository_type(repository)
|
52
|
+
jblob = RJGit.blob_type(blob)
|
53
|
+
# Try to resolve symlinks; return nil otherwise
|
54
|
+
mode = RJGit.get_file_mode(jrepo, jblob)
|
55
|
+
if mode == SYMLINK_TYPE
|
56
|
+
symlink_source = jrepo.open(jblob.id).get_bytes.to_a.pack('c*').force_encoding('UTF-8')
|
57
|
+
blob = Blob.find_blob(jrepo, symlink_source)
|
58
|
+
return nil if blob.nil?
|
59
|
+
jblob = blob.jblob
|
60
|
+
end
|
61
|
+
bytes = jrepo.open(jblob.id).get_bytes
|
48
62
|
return bytes.to_a.pack('c*').force_encoding('UTF-8')
|
49
63
|
end
|
50
64
|
|
@@ -75,7 +89,7 @@ module RJGit
|
|
75
89
|
entries << entry
|
76
90
|
end
|
77
91
|
options[:io].puts RJGit.stringify(entries) if options[:print]
|
78
|
-
entries
|
92
|
+
return entries
|
79
93
|
end
|
80
94
|
|
81
95
|
def self.blame(repository, file_path, options={})
|
@@ -90,9 +104,9 @@ module RJGit
|
|
90
104
|
blame = []
|
91
105
|
for index in (0..content.size - 1) do
|
92
106
|
blameline = {}
|
93
|
-
blameline[:actor] = Actor.
|
107
|
+
blameline[:actor] = Actor.new_from_person_ident(result.get_source_author(index))
|
94
108
|
blameline[:line] = result.get_source_line(index)
|
95
|
-
blameline[:commit] = Commit.new(result.get_source_commit(index))
|
109
|
+
blameline[:commit] = Commit.new(repository, result.get_source_commit(index))
|
96
110
|
blameline[:line] = content.get_string(index)
|
97
111
|
blame << blameline
|
98
112
|
end
|
@@ -112,7 +126,180 @@ module RJGit
|
|
112
126
|
diff_entries = diff_command.call
|
113
127
|
diff_entries = diff_entries.to_array.to_ary
|
114
128
|
diff_entries = RJGit.convert_diff_entries(diff_entries)
|
115
|
-
diff_entries
|
129
|
+
return diff_entries
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
module Plumbing
|
135
|
+
import org.eclipse.jgit.lib.Constants
|
136
|
+
|
137
|
+
class TreeBuilder
|
138
|
+
import org.eclipse.jgit.lib.FileMode
|
139
|
+
import org.eclipse.jgit.lib.TreeFormatter
|
140
|
+
|
141
|
+
|
142
|
+
attr_accessor :treemap
|
143
|
+
attr_reader :log
|
144
|
+
|
145
|
+
def initialize(repository)
|
146
|
+
@jrepo = RJGit.repository_type(repository)
|
147
|
+
@treemap = {}
|
148
|
+
init_log
|
149
|
+
end
|
150
|
+
|
151
|
+
def object_inserter
|
152
|
+
@jrepo.newObjectInserter
|
153
|
+
end
|
154
|
+
|
155
|
+
def init_log
|
156
|
+
@log = {:deleted => [], :added => [] }
|
157
|
+
end
|
158
|
+
|
159
|
+
def only_contains_deletions(hashmap)
|
160
|
+
hashmap.each do |key, value|
|
161
|
+
if value.is_a?(Hash) then
|
162
|
+
return false unless only_contains_deletions(value)
|
163
|
+
elsif value.is_a?(String)
|
164
|
+
return false
|
165
|
+
end
|
166
|
+
end
|
167
|
+
true
|
168
|
+
end
|
169
|
+
|
170
|
+
def build_tree(start_tree, treemap = nil, flush = false)
|
171
|
+
existing_trees = {}
|
172
|
+
formatter = TreeFormatter.new
|
173
|
+
treemap ||= self.treemap
|
174
|
+
|
175
|
+
if start_tree then
|
176
|
+
treewalk = TreeWalk.new(@jrepo)
|
177
|
+
treewalk.add_tree(start_tree)
|
178
|
+
while treewalk.next
|
179
|
+
filename = treewalk.get_name_string
|
180
|
+
if treemap.keys.include?(filename) then
|
181
|
+
kind = treewalk.isSubtree ? :tree : :blob
|
182
|
+
if treemap[filename] == false then
|
183
|
+
@log[:deleted] << [kind, filename, treewalk.get_object_id(0)]
|
184
|
+
else
|
185
|
+
existing_trees[filename] = treewalk.get_object_id(0) if kind == :tree
|
186
|
+
end
|
187
|
+
else
|
188
|
+
mode = treewalk.isSubtree ? FileMode::TREE : FileMode::REGULAR_FILE
|
189
|
+
formatter.append(filename.to_java_string, treewalk.get_file_mode(0), treewalk.get_object_id(0))
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
treemap.each do |object_name, data|
|
195
|
+
case data
|
196
|
+
when String
|
197
|
+
blobid = write_blob(data)
|
198
|
+
formatter.append(object_name.to_java_string, FileMode::REGULAR_FILE, blobid)
|
199
|
+
@log[:added] << [:blob, object_name, blobid]
|
200
|
+
when Hash
|
201
|
+
next_tree = build_tree(existing_trees[object_name], data)
|
202
|
+
formatter.append(object_name.to_java_string, FileMode::TREE, next_tree)
|
203
|
+
@log[:added] << [:tree, object_name, next_tree] unless only_contains_deletions(data)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
result = object_inserter.insert(formatter)
|
208
|
+
end
|
209
|
+
|
210
|
+
def write_blob(contents, flush = false)
|
211
|
+
blobid = object_inserter.insert(Constants::OBJ_BLOB, contents.to_java_bytes)
|
212
|
+
blobid
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
216
|
+
|
217
|
+
class Index
|
218
|
+
import org.eclipse.jgit.lib.CommitBuilder
|
219
|
+
|
220
|
+
attr_accessor :treemap, :current_tree
|
221
|
+
attr_reader :jrepo
|
222
|
+
|
223
|
+
def initialize(repository, branch = nil)
|
224
|
+
@treemap = {}
|
225
|
+
@jrepo = RJGit.repository_type(repository)
|
226
|
+
@treebuilder = TreeBuilder.new(@jrepo)
|
227
|
+
end
|
228
|
+
|
229
|
+
def add(path, data)
|
230
|
+
path = path[1..-1] if path[0] == '/'
|
231
|
+
path = path.split('/')
|
232
|
+
filename = path.pop
|
233
|
+
|
234
|
+
current = self.treemap
|
235
|
+
|
236
|
+
path.each do |dir|
|
237
|
+
current[dir] ||= {}
|
238
|
+
node = current[dir]
|
239
|
+
current = node
|
240
|
+
end
|
241
|
+
|
242
|
+
current[filename] = data
|
243
|
+
@treemap
|
244
|
+
end
|
245
|
+
|
246
|
+
def delete(path)
|
247
|
+
path = path[1..-1] if path[0] == '/'
|
248
|
+
path = path.split('/')
|
249
|
+
last = path.pop
|
250
|
+
|
251
|
+
current = self.treemap
|
252
|
+
|
253
|
+
path.each do |dir|
|
254
|
+
current[dir] ||= {}
|
255
|
+
node = current[dir]
|
256
|
+
current = node
|
257
|
+
end
|
258
|
+
|
259
|
+
current[last] = false
|
260
|
+
@treemap
|
261
|
+
end
|
262
|
+
|
263
|
+
def do_commit(message, author, parents, new_tree)
|
264
|
+
commit_builder = CommitBuilder.new
|
265
|
+
person = author.person_ident
|
266
|
+
commit_builder.setCommitter(person)
|
267
|
+
commit_builder.setAuthor(person)
|
268
|
+
commit_builder.setMessage(message)
|
269
|
+
commit_builder.setTreeId(RJGit.tree_type(new_tree))
|
270
|
+
if parents.is_a?(Array) then
|
271
|
+
parents.each {|parent| commit_builder.addParentId(RJGit.commit_type(parent)) }
|
272
|
+
elsif parents
|
273
|
+
commit_builder.addParentId(RJGit.commit_type(parents))
|
274
|
+
end
|
275
|
+
@treebuilder.object_inserter.insert(commit_builder)
|
276
|
+
end
|
277
|
+
|
278
|
+
def commit(message, author, parents = nil, ref = "refs/heads/#{Constants::MASTER}")
|
279
|
+
@current_tree = @current_tree ? RJGit.tree_type(@current_tree) : @jrepo.resolve("refs/heads/#{Constants::MASTER}^{tree}")
|
280
|
+
@treebuilder.treemap = @treemap
|
281
|
+
new_tree = @treebuilder.build_tree(@current_tree)
|
282
|
+
return false if @current_tree && new_tree.name == @current_tree.name
|
283
|
+
|
284
|
+
parents = parents ? parents : @jrepo.resolve(ref+"^{commit}")
|
285
|
+
new_head = do_commit(message, author, parents, new_tree)
|
286
|
+
|
287
|
+
# Point ref to the newest commit
|
288
|
+
ru = @jrepo.updateRef(ref)
|
289
|
+
ru.setNewObjectId(new_head)
|
290
|
+
res = ru.forceUpdate.to_string
|
291
|
+
|
292
|
+
@current_tree = new_tree
|
293
|
+
@treemap = {}
|
294
|
+
log = @treebuilder.log
|
295
|
+
@treebuilder.init_log
|
296
|
+
return res, log
|
297
|
+
end
|
298
|
+
|
299
|
+
def self.successful?(result)
|
300
|
+
["NEW", "FAST_FORWARD"].include?(result)
|
301
|
+
end
|
302
|
+
|
116
303
|
end
|
117
304
|
|
118
305
|
end
|
data/lib/rjgit_helpers.rb
CHANGED
@@ -16,11 +16,29 @@ module RJGit
|
|
16
16
|
def_delegators delegate_name, *java_methods
|
17
17
|
end
|
18
18
|
|
19
|
-
def self.
|
20
|
-
treewalk = TreeWalk.forPath(
|
19
|
+
def self.get_file_mode_with_path(jrepo, path, jtree)
|
20
|
+
treewalk = TreeWalk.forPath(jrepo, path, jtree)
|
21
21
|
return treewalk.get_file_mode(0).get_bits
|
22
22
|
end
|
23
23
|
|
24
|
+
def self.get_file_mode(jrepo, jblob, revstring=Constants::HEAD)
|
25
|
+
last_commit_hash = jrepo.resolve(revstring)
|
26
|
+
return nil if last_commit_hash.nil?
|
27
|
+
walk = RevWalk.new(jrepo)
|
28
|
+
jcommit = walk.parse_commit(last_commit_hash)
|
29
|
+
treewalk = TreeWalk.new(jrepo)
|
30
|
+
jtree = jcommit.get_tree
|
31
|
+
treewalk.add_tree(jtree)
|
32
|
+
treewalk.set_recursive(true)
|
33
|
+
while treewalk.next
|
34
|
+
jblob_lookup = walk.lookup_blob(treewalk.objectId(0))
|
35
|
+
if jblob_lookup.get_name == jblob.get_name
|
36
|
+
mode = treewalk.get_file_mode(0).get_bits
|
37
|
+
return mode
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
24
42
|
def self.stringify(entries)
|
25
43
|
str = ""
|
26
44
|
entries.each do |entry|
|
@@ -49,6 +67,18 @@ module RJGit
|
|
49
67
|
entry
|
50
68
|
end
|
51
69
|
|
70
|
+
def self.sym_for_type(type)
|
71
|
+
result = case type
|
72
|
+
when Constants::OBJ_BLOB
|
73
|
+
:blob
|
74
|
+
when Constants::OBJ_TREE
|
75
|
+
:tree
|
76
|
+
when Constants::OBJ_COMMIT
|
77
|
+
:commit
|
78
|
+
when Constants::OBJ_TAG
|
79
|
+
:tag
|
80
|
+
end
|
81
|
+
end
|
52
82
|
|
53
83
|
def self.repository_type(repository)
|
54
84
|
repo = case repository
|
@@ -70,6 +100,23 @@ module RJGit
|
|
70
100
|
treeobj = case tree
|
71
101
|
when Tree then tree.jtree
|
72
102
|
when org.eclipse.jgit.revwalk.RevTree then tree
|
103
|
+
when org.eclipse.jgit.lib.ObjectId then tree
|
104
|
+
else nil
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.blob_type(blob)
|
109
|
+
blobobj = case blob
|
110
|
+
when Blob then blob.jblob
|
111
|
+
when org.eclipse.jgit.revwalk.RevBlob then blob
|
112
|
+
else nil
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.commit_type(commit)
|
117
|
+
commitobj = case commit
|
118
|
+
when Commit then commit.jcommit
|
119
|
+
when org.eclipse.jgit.lib.ObjectId then commit
|
73
120
|
else nil
|
74
121
|
end
|
75
122
|
end
|
data/lib/tag.rb
CHANGED
@@ -22,7 +22,7 @@ module RJGit
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def actor
|
25
|
-
@actor ||= Actor.
|
25
|
+
@actor ||= Actor.new_from_person_ident(@jtag.get_tagger_ident)
|
26
26
|
end
|
27
27
|
|
28
28
|
def name
|
@@ -33,6 +33,13 @@ module RJGit
|
|
33
33
|
@type ||= @jtag.get_type
|
34
34
|
end
|
35
35
|
|
36
|
+
def object
|
37
|
+
@object ||= @jtag.get_object
|
38
|
+
end
|
39
|
+
|
40
|
+
def object_type
|
41
|
+
@object_type ||= object.get_type
|
42
|
+
end
|
36
43
|
|
37
44
|
end
|
38
45
|
end
|
data/lib/tree.rb
CHANGED
@@ -7,26 +7,70 @@ module RJGit
|
|
7
7
|
|
8
8
|
attr_reader :contents, :id, :mode, :name, :repo, :jtree
|
9
9
|
RJGit.delegate_to(RevTree, :@jtree)
|
10
|
+
include Enumerable
|
10
11
|
|
11
12
|
def initialize(repository, mode, path, jtree)
|
12
|
-
@
|
13
|
+
@jrepo = RJGit.repository_type(repository)
|
13
14
|
@mode = mode
|
14
15
|
@path = path
|
15
|
-
@name = File.basename(path)
|
16
|
+
@name = @path ? File.basename(path) : nil
|
16
17
|
@jtree = jtree
|
17
18
|
@id = ObjectId.to_string(jtree.get_id)
|
18
19
|
end
|
19
20
|
|
20
21
|
def data
|
22
|
+
return @contents if @contents
|
21
23
|
strio = StringIO.new
|
22
|
-
RJGit::Porcelain.ls_tree(@
|
23
|
-
strio.string
|
24
|
+
RJGit::Porcelain.ls_tree(@jrepo, @jtree, options={:print => true, :io => strio})
|
25
|
+
@contents = strio.string
|
24
26
|
end
|
25
27
|
|
26
|
-
def
|
28
|
+
def contents_array
|
29
|
+
return @contents_ary if @contents_ary
|
30
|
+
results = []
|
31
|
+
RJGit::Porcelain.ls_tree(@jrepo, @jtree).each do |item|
|
32
|
+
walk = RevWalk.new(@jrepo)
|
33
|
+
results << Tree.new(@jrepo, item[:mode], item[:path], walk.lookup_tree(ObjectId.from_string(item[:id]))) if item[:type] == 'tree'
|
34
|
+
results << Blob.new(@jrepo, item[:mode], item[:path], walk.lookup_blob(ObjectId.from_string(item[:id]))) if item[:type] == 'blob'
|
35
|
+
end
|
36
|
+
@contents_ary = results
|
37
|
+
end
|
38
|
+
|
39
|
+
def each(&block)
|
40
|
+
contents_array.each(&block)
|
41
|
+
end
|
42
|
+
|
43
|
+
def blobs
|
44
|
+
contents_array.select {|x| x.is_a?(Blob)}
|
45
|
+
end
|
46
|
+
|
47
|
+
def trees
|
48
|
+
contents_array.select {|x| x.is_a?(Tree)}
|
49
|
+
end
|
50
|
+
|
51
|
+
# From Grit
|
52
|
+
def /(file)
|
53
|
+
if file =~ /\//
|
54
|
+
file.split("/").inject(self) { |acc, x| acc/x } rescue nil
|
55
|
+
else
|
56
|
+
self.contents_array.find { |c| c.name == file }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.new_from_hashmap(repository, hashmap, base_tree = nil)
|
61
|
+
jrepo = RJGit.repository_type(repository)
|
62
|
+
tree_builder = Plumbing::TreeBuilder.new(jrepo)
|
63
|
+
base_tree = RJGit.tree_type(base_tree)
|
64
|
+
new_tree = tree_builder.build_tree(base_tree, hashmap, true)
|
65
|
+
walk = RevWalk.new(jrepo)
|
66
|
+
new_tree = walk.lookup_tree(new_tree)
|
67
|
+
Tree.new(jrepo, FileMode::TREE, nil, new_tree)
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.find_tree(repository, file_path, revstring=Constants::HEAD)
|
27
71
|
jrepo = RJGit.repository_type(repository)
|
28
72
|
return nil if jrepo.nil?
|
29
|
-
last_commit_hash = jrepo.resolve(
|
73
|
+
last_commit_hash = jrepo.resolve(revstring)
|
30
74
|
return nil if last_commit_hash.nil?
|
31
75
|
|
32
76
|
walk = RevWalk.new(jrepo)
|
@@ -38,7 +82,7 @@ module RJGit
|
|
38
82
|
if treewalk.next
|
39
83
|
jsubtree = walk.lookup_tree(treewalk.object_id(0))
|
40
84
|
if jsubtree
|
41
|
-
mode = RJGit.
|
85
|
+
mode = RJGit.get_file_mode_with_path(jrepo, file_path, jtree)
|
42
86
|
Tree.new(jrepo, mode, file_path, jsubtree)
|
43
87
|
end
|
44
88
|
else
|
data/lib/version.rb
CHANGED
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rjgit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
version: 0.2.0
|
4
|
+
version: 0.3.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Maarten Engelen
|
@@ -13,7 +12,7 @@ authors:
|
|
13
12
|
autorequire:
|
14
13
|
bindir: bin
|
15
14
|
cert_chain: []
|
16
|
-
date: 2013-
|
15
|
+
date: 2013-12-08 00:00:00.000000000 Z
|
17
16
|
dependencies:
|
18
17
|
- !ruby/object:Gem::Dependency
|
19
18
|
name: mime-types
|
@@ -22,13 +21,11 @@ dependencies:
|
|
22
21
|
- - ~>
|
23
22
|
- !ruby/object:Gem::Version
|
24
23
|
version: '1.15'
|
25
|
-
none: false
|
26
24
|
requirement: !ruby/object:Gem::Requirement
|
27
25
|
requirements:
|
28
26
|
- - ~>
|
29
27
|
- !ruby/object:Gem::Version
|
30
28
|
version: '1.15'
|
31
|
-
none: false
|
32
29
|
prerelease: false
|
33
30
|
type: :runtime
|
34
31
|
description: JRuby wrapper around the JGit library for manipulating git repositories in code.
|
@@ -55,11 +52,12 @@ files:
|
|
55
52
|
- LICENSE
|
56
53
|
- Gemfile
|
57
54
|
- lib/java/jars/jsch-0.1.49.jar
|
58
|
-
- lib/java/jars/org.eclipse.jgit-3.
|
55
|
+
- lib/java/jars/org.eclipse.jgit-3.1.0.201310021548-r.jar
|
59
56
|
homepage: https://github.com/repotag/rjgit
|
60
57
|
licenses:
|
61
58
|
- Modified BSD
|
62
59
|
- EPL
|
60
|
+
metadata: {}
|
63
61
|
post_install_message:
|
64
62
|
rdoc_options:
|
65
63
|
- --charset=UTF-8
|
@@ -69,21 +67,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
69
67
|
requirements:
|
70
68
|
- - '>='
|
71
69
|
- !ruby/object:Gem::Version
|
72
|
-
segments:
|
73
|
-
- 0
|
74
|
-
hash: 2
|
75
70
|
version: '0'
|
76
|
-
none: false
|
77
71
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
72
|
requirements:
|
79
73
|
- - '>='
|
80
74
|
- !ruby/object:Gem::Version
|
81
75
|
version: '0'
|
82
|
-
none: false
|
83
76
|
requirements: []
|
84
77
|
rubyforge_project:
|
85
|
-
rubygems_version: 1.
|
78
|
+
rubygems_version: 2.1.9
|
86
79
|
signing_key:
|
87
|
-
specification_version:
|
80
|
+
specification_version: 4
|
88
81
|
summary: JRuby wrapper around the JGit library.
|
89
82
|
test_files: []
|
Binary file
|