rjgit 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +8 -0
- data/LICENSE +46 -0
- data/README.md +156 -0
- data/lib/actor.rb +55 -0
- data/lib/blob.rb +76 -0
- data/lib/commit.rb +56 -0
- data/lib/config.rb +94 -0
- data/lib/constants.rb +16 -0
- data/lib/git.rb +228 -0
- data/lib/java/jars/jsch-0.1.49.jar +0 -0
- data/lib/java/jars/org.eclipse.jgit-2.3.1.201302201838-r.jar +0 -0
- data/lib/repo.rb +171 -0
- data/lib/rjgit.rb +122 -0
- data/lib/rjgit_helpers.rb +77 -0
- data/lib/tag.rb +38 -0
- data/lib/transport.rb +79 -0
- data/lib/tree.rb +51 -0
- data/lib/version.rb +3 -0
- metadata +86 -0
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# RJGit
|
2
|
+
|
3
|
+
Copyright (c) 2013, Team Repotag
|
4
|
+
|
5
|
+
(Modified BSD License)
|
6
|
+
|
7
|
+
All rights reserved.
|
8
|
+
|
9
|
+
Redistribution and use in source and binary forms, with or without
|
10
|
+
modification, are permitted provided that the following conditions are met:
|
11
|
+
|
12
|
+
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
13
|
+
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
14
|
+
* Neither the name of Team Repotag nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
17
|
+
|
18
|
+
# JGit
|
19
|
+
|
20
|
+
Eclipse Distribution License - v 1.0
|
21
|
+
|
22
|
+
Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors.
|
23
|
+
|
24
|
+
All rights reserved.
|
25
|
+
|
26
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
27
|
+
|
28
|
+
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
29
|
+
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
30
|
+
* Neither the name of the Eclipse Foundation, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
31
|
+
|
32
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
|
34
|
+
# JSch
|
35
|
+
|
36
|
+
Copyright (c) 2002-2012 Atsuhiko Yamanaka, JCraft,Inc.
|
37
|
+
All rights reserved.
|
38
|
+
|
39
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
40
|
+
|
41
|
+
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
42
|
+
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
43
|
+
* The names of the authors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
44
|
+
|
45
|
+
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
46
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
JGit
|
2
|
+
=====
|
3
|
+
|
4
|
+
###A JRuby wrapper around the [JGit library](https://github.com/eclipse/jgit) for manipulating Git repositories, the Ruby way.
|
5
|
+
|
6
|
+
Authors
|
7
|
+
-------
|
8
|
+
|
9
|
+
RJGit is being developed by Team Repotag:
|
10
|
+
|
11
|
+
- [Maarten Engelen](https://github.com/maarten)
|
12
|
+
- [Bart Kamphorst](https://github.com/bartkamphorst)
|
13
|
+
- [Dawa Ometto](https://github.com/dometto)
|
14
|
+
- [Arlette van Wissen](https://github.com/arlettevanwissen)
|
15
|
+
- [Steven Woudenberg](https://github.com/stevenwoudenberg)
|
16
|
+
|
17
|
+
With special thanks to:
|
18
|
+
- Patrick Pepels
|
19
|
+
|
20
|
+
Installation
|
21
|
+
------------
|
22
|
+
Install the rjgit gem with the command:
|
23
|
+
|
24
|
+
$ gem install rjgit
|
25
|
+
|
26
|
+
#### Dependencies for using RJGit:
|
27
|
+
- JRuby >= 1.7.0
|
28
|
+
- mime-types >= 1.15
|
29
|
+
|
30
|
+
#### Further dependencies for developing RJGIT:
|
31
|
+
- rake >= 0.9.2.2
|
32
|
+
- rspec >= 2.0
|
33
|
+
- simplecov
|
34
|
+
|
35
|
+
Usage
|
36
|
+
-----
|
37
|
+
RJGit wraps most (if not all) of JGit's core functionality; see below for some examples of what you can do with it. Make sure you have [JRuby](http://jruby.org/) installed.
|
38
|
+
|
39
|
+
### Require the gem and include the RJGit module
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
require "rjgit"
|
43
|
+
include RJGit
|
44
|
+
```
|
45
|
+
|
46
|
+
### Initializing an existing repository on the filesystem
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
repo = Repo.new("repo.git")
|
50
|
+
```
|
51
|
+
|
52
|
+
### Creating a new repository
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
repo = Repo.new("repo.git", :create => true)
|
56
|
+
repo = Repo.new("repo.git", :create => true, :bare => true) # Create a 'bare' git repo, which stores all git-data under the '.git' directory.
|
57
|
+
```
|
58
|
+
|
59
|
+
### Getting a list of commits
|
60
|
+
```ruby
|
61
|
+
repo.commits('master')
|
62
|
+
repo.commits('959329025f67539fb82e76b02782322fad032821')
|
63
|
+
# Similarly for getting tags, branches, trees (directories), and blobs (files).
|
64
|
+
```
|
65
|
+
|
66
|
+
### Getting tags
|
67
|
+
```ruby
|
68
|
+
tag = repo.tags['example_tag']
|
69
|
+
tag.id # tag's object id
|
70
|
+
tag.author.name # Etcetera
|
71
|
+
```
|
72
|
+
|
73
|
+
### Getting a repository's contents
|
74
|
+
```ruby
|
75
|
+
repo.blob("example/file.txt") # Retrieve a file by filepath
|
76
|
+
repo.blob("example/file.txt").data # Cat the file
|
77
|
+
repo.tree("example") # Retrieve a tree by filepath
|
78
|
+
repo.tree("example").data # List the tree's contents (blobs and trees)
|
79
|
+
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.
|
80
|
+
```
|
81
|
+
|
82
|
+
### Manipulating repositories
|
83
|
+
```ruby
|
84
|
+
repo.create_branch('new_branch') # Similarly for deleting, renaming
|
85
|
+
repo.checkout('new_branch')
|
86
|
+
repo.add('new_file.txt') # Similarly for removing
|
87
|
+
repo.commit('My message')
|
88
|
+
```
|
89
|
+
|
90
|
+
### And more...
|
91
|
+
```ruby
|
92
|
+
pack = RJGitReceivePack.new(repo) # Implement the smart-http protocol with RJGitReceivePack and RJGitUploadPack
|
93
|
+
pack.receive(client_msg) # Respond to a client's GET request
|
94
|
+
repo.config['remote origin']['url'] # Retrieve config values
|
95
|
+
Porcelain::diff(repo, options)
|
96
|
+
Porcelain::blame(repo, options)
|
97
|
+
```
|
98
|
+
|
99
|
+
Issues
|
100
|
+
---------------
|
101
|
+
Please let us know by creating a [github issue](https://github.com/repotag/rjgit/issues).
|
102
|
+
|
103
|
+
Contributing
|
104
|
+
---------------
|
105
|
+
|
106
|
+
|
107
|
+
1. Fork the project
|
108
|
+
1. Create a new branch
|
109
|
+
1. Modify the sources
|
110
|
+
1. Add specs with full coverage for your new code
|
111
|
+
1. Make sure the whole test suite passes by running rake
|
112
|
+
1. Push the branch up to GitHub
|
113
|
+
1. Send us a pull request
|
114
|
+
|
115
|
+
Running RSpec tests (the recommended way)
|
116
|
+
---------------
|
117
|
+
|
118
|
+
1. Start the nailgun server
|
119
|
+
```
|
120
|
+
jruby --ng-server &
|
121
|
+
```
|
122
|
+
1. Run rake against the nailgun instance
|
123
|
+
```
|
124
|
+
jruby --ng -S rake
|
125
|
+
```
|
126
|
+
|
127
|
+
License
|
128
|
+
-------
|
129
|
+
Copyright (c) 2011 - 2013, Team Repotag
|
130
|
+
|
131
|
+
(Modified BSD License)
|
132
|
+
|
133
|
+
All rights reserved.
|
134
|
+
|
135
|
+
Redistribution and use in source and binary forms, with or without
|
136
|
+
modification, are permitted provided that the following conditions are met:
|
137
|
+
|
138
|
+
* Redistributions of source code must retain the above copyright
|
139
|
+
notice, this list of conditions and the following disclaimer.
|
140
|
+
* Redistributions in binary form must reproduce the above copyright
|
141
|
+
notice, this list of conditions and the following disclaimer in the
|
142
|
+
documentation and/or other materials provided with the distribution.
|
143
|
+
* Neither the name of the organization nor the
|
144
|
+
names of its contributors may be used to endorse or promote products
|
145
|
+
derived from this software without specific prior written permission.
|
146
|
+
|
147
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
148
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
149
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
150
|
+
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
151
|
+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
152
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
153
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
154
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
155
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
156
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/lib/actor.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module RJGit
|
2
|
+
|
3
|
+
# PersonIdent in JGit
|
4
|
+
import 'org.eclipse.jgit.lib.PersonIdent'
|
5
|
+
|
6
|
+
class Actor
|
7
|
+
|
8
|
+
attr_reader :name, :email, :person_ident
|
9
|
+
|
10
|
+
RJGit.delegate_to(PersonIdent, :@person_ident)
|
11
|
+
|
12
|
+
def self.new_from_name_and_email(name, email)
|
13
|
+
return self.new(PersonIdent.new(name, email))
|
14
|
+
end
|
15
|
+
alias_method :to_s, :name
|
16
|
+
|
17
|
+
def initialize(person_ident)
|
18
|
+
@name = person_ident.get_name
|
19
|
+
@email = person_ident.get_email_address
|
20
|
+
@person_ident = person_ident
|
21
|
+
end
|
22
|
+
|
23
|
+
# Create an Actor from a string.
|
24
|
+
#
|
25
|
+
# str - The String in this format: 'John Doe <jdoe@example.com>'
|
26
|
+
#
|
27
|
+
# Returns Git::Actor.
|
28
|
+
def self.from_string(str)
|
29
|
+
if str =~ /<.+>/
|
30
|
+
m, name, email = *str.match(/(.*) <(.+?)>/)
|
31
|
+
return self.new_from_name_and_email(name, email)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Outputs an actor string for Git commits.
|
36
|
+
#
|
37
|
+
# actor = Actor.new('bob', 'bob@email.com')
|
38
|
+
# actor.output(time) # => "bob <bob@email.com> UNIX_TIME +0700"
|
39
|
+
#
|
40
|
+
# time - The Time the commit was authored or committed.
|
41
|
+
#
|
42
|
+
# Returns a String.
|
43
|
+
def output(time)
|
44
|
+
offset = time.utc_offset / 60
|
45
|
+
"%s <%s> %d %+.2d%.2d" % [
|
46
|
+
@name,
|
47
|
+
@email || "null",
|
48
|
+
time.to_i,
|
49
|
+
offset / 60,
|
50
|
+
offset.abs % 60]
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
data/lib/blob.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
module RJGit
|
2
|
+
|
3
|
+
import 'org.eclipse.jgit.revwalk.RevBlob'
|
4
|
+
|
5
|
+
class Blob
|
6
|
+
|
7
|
+
attr_reader :id, :mode, :name, :path, :jblob
|
8
|
+
RJGit.delegate_to(RevBlob, :@jblob)
|
9
|
+
|
10
|
+
def initialize(jrepo, path, mode, jblob)
|
11
|
+
@jrepo = jrepo
|
12
|
+
@jblob = jblob
|
13
|
+
@path = path
|
14
|
+
@name = File.basename(path)
|
15
|
+
@mode = mode
|
16
|
+
@id = ObjectId.toString(jblob.get_id)
|
17
|
+
end
|
18
|
+
|
19
|
+
# The size of this blob in bytes
|
20
|
+
#
|
21
|
+
# Returns Integer
|
22
|
+
def bytesize
|
23
|
+
@bytesize ||= @jrepo.open(@jblob).get_size
|
24
|
+
end
|
25
|
+
|
26
|
+
def size
|
27
|
+
@size ||= bytesize
|
28
|
+
end
|
29
|
+
|
30
|
+
def blame(options={})
|
31
|
+
@blame ||= RJGit::Porcelain.blame(@jrepo, @path, options)
|
32
|
+
end
|
33
|
+
|
34
|
+
# The binary contents of this blob.
|
35
|
+
# Returns String
|
36
|
+
def data
|
37
|
+
@data ||= RJGit::Porcelain.cat_file(@jrepo, @jblob)
|
38
|
+
end
|
39
|
+
|
40
|
+
# The mime type of this file (based on the filename)
|
41
|
+
# Returns String
|
42
|
+
def mime_type
|
43
|
+
Blob.mime_type(self.name)
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.mime_type(filename)
|
47
|
+
guesses = MIME::Types.type_for(filename) rescue []
|
48
|
+
guesses.first ? guesses.first.simplified : DEFAULT_MIME_TYPE
|
49
|
+
end
|
50
|
+
|
51
|
+
# Finds a particular Blob in repository matching file_path
|
52
|
+
def self.find_blob(repository, file_path, branch=Constants::HEAD)
|
53
|
+
jrepo = RJGit.repository_type(repository)
|
54
|
+
last_commit_hash = jrepo.resolve(branch)
|
55
|
+
return nil if last_commit_hash.nil?
|
56
|
+
|
57
|
+
walk = RevWalk.new(jrepo)
|
58
|
+
jcommit = walk.parse_commit(last_commit_hash)
|
59
|
+
treewalk = TreeWalk.new(jrepo)
|
60
|
+
jtree = jcommit.get_tree
|
61
|
+
treewalk.add_tree(jtree)
|
62
|
+
treewalk.set_recursive(true)
|
63
|
+
treewalk.set_filter(PathFilter.create(file_path))
|
64
|
+
if treewalk.next
|
65
|
+
jblob = walk.lookup_blob(treewalk.objectId(0))
|
66
|
+
if jblob
|
67
|
+
mode = RJGit.get_file_mode(jrepo, file_path, jtree)
|
68
|
+
Blob.new(jrepo, file_path, mode, jblob)
|
69
|
+
end
|
70
|
+
else
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
data/lib/commit.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module RJGit
|
2
|
+
|
3
|
+
import 'org.eclipse.jgit.revwalk.RevWalk'
|
4
|
+
import 'org.eclipse.jgit.revwalk.RevCommit'
|
5
|
+
|
6
|
+
class Commit
|
7
|
+
|
8
|
+
attr_reader :id
|
9
|
+
attr_reader :parents
|
10
|
+
attr_reader :actor
|
11
|
+
attr_reader :committer
|
12
|
+
attr_reader :authored_date
|
13
|
+
attr_reader :committed_date
|
14
|
+
attr_reader :message
|
15
|
+
attr_reader :short_message
|
16
|
+
attr_reader :jcommit
|
17
|
+
attr_reader :count
|
18
|
+
|
19
|
+
RJGit.delegate_to(RevCommit, :@jcommit)
|
20
|
+
|
21
|
+
def initialize(commit)
|
22
|
+
@jcommit = commit
|
23
|
+
@id = ObjectId.to_string(commit.get_id)
|
24
|
+
@actor = Actor.new(@jcommit.get_author_ident)
|
25
|
+
@committer = Actor.new(@jcommit.get_committer_ident)
|
26
|
+
@committed_date = Time.at(@jcommit.commit_time)
|
27
|
+
@message = @jcommit.get_full_message
|
28
|
+
@short_message = @jcommit.get_short_message
|
29
|
+
@count = @jcommit.get_parent_count
|
30
|
+
end
|
31
|
+
|
32
|
+
def parents
|
33
|
+
@parents ||= @jcommit.get_parents.map{|parent| Commit.new(parent) }
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.find_all(repository, ref, options)
|
37
|
+
repository = RJGit.repository_type(repository)
|
38
|
+
return nil if repository.nil?
|
39
|
+
begin
|
40
|
+
walk = RevWalk.new(repository)
|
41
|
+
objhead = repository.resolve(ref)
|
42
|
+
root = walk.parse_commit(objhead)
|
43
|
+
walk.mark_start(root)
|
44
|
+
commits = walk.map { |commit| Commit.new(commit) }
|
45
|
+
return commits.first(options[:limit])
|
46
|
+
rescue NativeException => e
|
47
|
+
return Array.new
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.diff(repo, a, b = nil, paths = [], options = {})
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
data/lib/config.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
module RJGit
|
2
|
+
|
3
|
+
import 'org.eclipse.jgit.lib.Config'
|
4
|
+
|
5
|
+
class Configuration
|
6
|
+
|
7
|
+
attr_reader :jconfig, :path
|
8
|
+
|
9
|
+
def initialize(path)
|
10
|
+
@path = path
|
11
|
+
@jconfig = org.eclipse.jgit.lib.Config.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def load
|
15
|
+
return self if @loaded
|
16
|
+
begin
|
17
|
+
@jconfig.from_text(IO.read(@path))
|
18
|
+
@loaded = true
|
19
|
+
rescue => exception
|
20
|
+
@loaded = false
|
21
|
+
raise IOException.new(exception.message)
|
22
|
+
end
|
23
|
+
return self
|
24
|
+
end
|
25
|
+
|
26
|
+
def [](key)
|
27
|
+
section, subsection = key.split
|
28
|
+
build_settings_hash(section, subsection)
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_settings_hash(section, subsection)
|
32
|
+
names = names(section, subsection)
|
33
|
+
settings = {}
|
34
|
+
names.each do |name|
|
35
|
+
value = @jconfig.get_string(section, subsection, name)
|
36
|
+
if is_num?(value)
|
37
|
+
value = value.to_i
|
38
|
+
elsif is_bool?(value)
|
39
|
+
value = to_boolean(value)
|
40
|
+
end
|
41
|
+
settings[name] = value
|
42
|
+
end
|
43
|
+
settings
|
44
|
+
end
|
45
|
+
|
46
|
+
def is_num?(str)
|
47
|
+
begin
|
48
|
+
!!Integer(str)
|
49
|
+
rescue ArgumentError, TypeError
|
50
|
+
false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def is_bool?(str)
|
55
|
+
str = str.strip
|
56
|
+
str == 'true' || str == 'false'
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_boolean(str)
|
60
|
+
str == "true"
|
61
|
+
end
|
62
|
+
|
63
|
+
def loaded?
|
64
|
+
@loaded
|
65
|
+
end
|
66
|
+
|
67
|
+
def sections
|
68
|
+
@jconfig.get_sections.to_array
|
69
|
+
end
|
70
|
+
|
71
|
+
def subsections(section)
|
72
|
+
@jconfig.get_subsections(section).to_array
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_s
|
76
|
+
@jconfig.to_text
|
77
|
+
end
|
78
|
+
|
79
|
+
def add_setting(name, value, section, subsection = "")
|
80
|
+
case value
|
81
|
+
when Integer then @jconfig.set_int(section, subsection, name, value)
|
82
|
+
when TrueClass then @jconfig.set_boolean(section, subsection, name, value)
|
83
|
+
when FalseClass then @jconfig.set_boolean(section, subsection, name, value)
|
84
|
+
when String then @jconfig.set_string(section, subsection, name, value)
|
85
|
+
else nil
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def names(section, subsection)
|
90
|
+
@jconfig.get_names(section, subsection).to_array
|
91
|
+
end
|
92
|
+
|
93
|
+
end # Config
|
94
|
+
end
|
data/lib/constants.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module RJGit
|
2
|
+
|
3
|
+
import 'org.eclipse.jgit.lib.FileMode'
|
4
|
+
|
5
|
+
TREE_TYPE = 0040000
|
6
|
+
SYMLINK_TYPE = 0120000
|
7
|
+
FILE_TYPE = 0100000
|
8
|
+
GITLINK_TYPE = 0160000
|
9
|
+
MISSING_TYPE = 0000000
|
10
|
+
REG_FILE_TYPE = 0100644
|
11
|
+
|
12
|
+
DEFAULT_MIME_TYPE = "text/plain"
|
13
|
+
|
14
|
+
OBJ_TAG = 4
|
15
|
+
|
16
|
+
end
|
data/lib/git.rb
ADDED
@@ -0,0 +1,228 @@
|
|
1
|
+
module RJGit
|
2
|
+
|
3
|
+
import 'java.io.ByteArrayInputStream'
|
4
|
+
import 'java.io.FileInputStream'
|
5
|
+
|
6
|
+
import 'org.eclipse.jgit.api.Git'
|
7
|
+
import 'org.eclipse.jgit.api.AddCommand'
|
8
|
+
import 'org.eclipse.jgit.api.RmCommand'
|
9
|
+
import 'org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider'
|
10
|
+
import 'org.eclipse.jgit.transport.RefSpec'
|
11
|
+
|
12
|
+
class RubyGit
|
13
|
+
|
14
|
+
attr_accessor :jgit
|
15
|
+
attr_accessor :jrepo
|
16
|
+
|
17
|
+
RESET_MODES = ["HARD", "SOFT", "KEEP", "MERGE", "MIXED"]
|
18
|
+
|
19
|
+
RJGit.delegate_to(Git, :@jgit)
|
20
|
+
|
21
|
+
def initialize(repository)
|
22
|
+
@jrepo = RJGit.repository_type(repository)
|
23
|
+
@jgit = Git.new(@jrepo)
|
24
|
+
end
|
25
|
+
|
26
|
+
def log
|
27
|
+
logs = @jgit.log
|
28
|
+
commits = Array.new
|
29
|
+
logs.call.each do |jcommit|
|
30
|
+
commits << Commit.new(jcommit)
|
31
|
+
end
|
32
|
+
commits
|
33
|
+
end
|
34
|
+
|
35
|
+
def branch_list
|
36
|
+
branch = @jgit.branch_list
|
37
|
+
array = Array.new
|
38
|
+
branch.call.each do |b|
|
39
|
+
array << b.get_name
|
40
|
+
end
|
41
|
+
array
|
42
|
+
end
|
43
|
+
|
44
|
+
def commit(message)
|
45
|
+
Commit.new(@jgit.commit.set_message(message).call)
|
46
|
+
end
|
47
|
+
|
48
|
+
def clone(remote, local, options = {})
|
49
|
+
RubyGit.clone(remote, local, options)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.clone(remote, local, options = {})
|
53
|
+
clone_command = Git.clone_repository
|
54
|
+
clone_command.setURI(remote)
|
55
|
+
clone_command.set_directory(java.io.File.new(local))
|
56
|
+
clone_command.set_bare(true) if options[:bare]
|
57
|
+
if options[:branch]
|
58
|
+
if options[:branch] == :all
|
59
|
+
clone_command.set_clone_all_branches(true)
|
60
|
+
else
|
61
|
+
clone_command.set_branch(options[:branch])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
if options[:username]
|
65
|
+
clone_command.set_credentials_provider(UsernamePasswordCredentialsProvider.new(options[:username], options[:password]))
|
66
|
+
end
|
67
|
+
clone_command.call
|
68
|
+
Repo.new(local)
|
69
|
+
end
|
70
|
+
|
71
|
+
def add(file_pattern)
|
72
|
+
@jgit.add.add_filepattern(file_pattern).call
|
73
|
+
end
|
74
|
+
|
75
|
+
def remove(file_pattern)
|
76
|
+
@jgit.rm.add_filepattern(file_pattern).call
|
77
|
+
end
|
78
|
+
|
79
|
+
def merge(commit)
|
80
|
+
merge_command = @jgit.merge
|
81
|
+
merge_command.include(commit.jcommit)
|
82
|
+
result = merge_command.call
|
83
|
+
if result.get_merge_status.to_string == 'Conflicting'
|
84
|
+
return result.get_conflicts.to_hash.keys
|
85
|
+
else
|
86
|
+
return result
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def tag(name, message = "", commit_or_revision = nil, actor = nil, force = false)
|
91
|
+
tag_command = @jgit.tag
|
92
|
+
tag_command.set_name(name)
|
93
|
+
tag_command.set_force_update(force)
|
94
|
+
tag_command.set_message(message)
|
95
|
+
tag_command.set_object_id(commit_or_revision) if commit_or_revision
|
96
|
+
if actor
|
97
|
+
actor = RJGit.actor_type(actor)
|
98
|
+
tag_command.set_tagger(actor)
|
99
|
+
end
|
100
|
+
tag_command.call
|
101
|
+
end
|
102
|
+
|
103
|
+
def resolve_tag(tagref)
|
104
|
+
begin
|
105
|
+
walk = RevWalk.new(@jrepo)
|
106
|
+
walk.parse_tag(tagref.get_object_id)
|
107
|
+
rescue Java::OrgEclipseJgitErrors::IncorrectObjectTypeException
|
108
|
+
nil
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def create_branch(name)
|
113
|
+
@jgit.branch_create.setName(name).call
|
114
|
+
end
|
115
|
+
|
116
|
+
def delete_branch(name)
|
117
|
+
@jgit.branch_delete.set_branch_names(name).call
|
118
|
+
end
|
119
|
+
|
120
|
+
def rename_branch(old_name, new_name)
|
121
|
+
@jgit.branch_rename.set_old_name(old_name).set_new_name(new_name).call
|
122
|
+
end
|
123
|
+
|
124
|
+
def checkout(branch_name, options = {})
|
125
|
+
checkout_command = @jgit.checkout.set_name(branch_name)
|
126
|
+
checkout_command.set_create_branch(true) if options[:create]
|
127
|
+
checkout_command.set_force(true) if options[:force]
|
128
|
+
result = {}
|
129
|
+
begin
|
130
|
+
checkout_command.call
|
131
|
+
result[:success] = true
|
132
|
+
result[:result] = @jgit.get_repository.get_full_branch
|
133
|
+
rescue Java::OrgEclipseJgitApiErrors::CheckoutConflictException => conflict
|
134
|
+
result[:success] = false
|
135
|
+
result[:result] = conflict.get_conflicting_paths
|
136
|
+
end
|
137
|
+
result
|
138
|
+
end
|
139
|
+
|
140
|
+
def apply(input_stream)
|
141
|
+
apply_result = @jgit.apply.set_patch(input_stream).call
|
142
|
+
updated_files = apply_result.get_updated_files
|
143
|
+
updated_files_parsed = []
|
144
|
+
updated_files.each do |file|
|
145
|
+
updated_files_parsed << file.get_absolute_path
|
146
|
+
end
|
147
|
+
updated_files_parsed
|
148
|
+
end
|
149
|
+
|
150
|
+
def apply_patch(patch_content)
|
151
|
+
input_stream = ByteArrayInputStream.new(patch_content.to_java_bytes)
|
152
|
+
apply(input_stream)
|
153
|
+
end
|
154
|
+
|
155
|
+
def apply_file(patch_file)
|
156
|
+
input_stream = FileInputStream.new(patch_file)
|
157
|
+
apply(input_stream)
|
158
|
+
end
|
159
|
+
|
160
|
+
def clean(options = {})
|
161
|
+
clean_command = @jgit.clean
|
162
|
+
clean_command.set_dry_run(true) if options[:dryrun]
|
163
|
+
clean_command.set_paths(java.util.Arrays.asList(options[:paths])) if options[:paths]
|
164
|
+
clean_command.call
|
165
|
+
end
|
166
|
+
|
167
|
+
def reset(ref, mode = "HARD", paths = nil)
|
168
|
+
return nil if mode != nil && !RESET_MODES.include?(mode)
|
169
|
+
reset_command = @jgit.reset
|
170
|
+
if paths then
|
171
|
+
paths.each do |path|
|
172
|
+
reset_command.addPath(path)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
reset_command.setRef(ref.id)
|
176
|
+
reset_command.setMode(org.eclipse.jgit.api.ResetCommand::ResetType.valueOf(mode)) unless mode == nil
|
177
|
+
reset_command.call
|
178
|
+
end
|
179
|
+
|
180
|
+
def revert(commits)
|
181
|
+
revert_command = @jgit.revert
|
182
|
+
commits.each do |commit|
|
183
|
+
revert_command.include commit.jcommit
|
184
|
+
end
|
185
|
+
Commit.new(revert_command.call)
|
186
|
+
end
|
187
|
+
|
188
|
+
def status
|
189
|
+
@jgit.status.call
|
190
|
+
end
|
191
|
+
|
192
|
+
def push_all(remote, options = {})
|
193
|
+
push_command = @jgit.push
|
194
|
+
push_command.set_dry_run(true) if options[:dryrun]
|
195
|
+
push_command.set_remote(remote)
|
196
|
+
push_command.set_push_all
|
197
|
+
push_command.set_push_tags
|
198
|
+
if options[:username]
|
199
|
+
push_command.set_credentials_provider(UsernamePasswordCredentialsProvider.new(options[:username], options[:password]))
|
200
|
+
end
|
201
|
+
push_command.call
|
202
|
+
end
|
203
|
+
|
204
|
+
def push(remote, refs = [], options = {})
|
205
|
+
if(refs.size > 0)
|
206
|
+
refs.map!{|ref| RefSpec.new(ref)}
|
207
|
+
push_command = @jgit.push
|
208
|
+
push_command.set_dry_run(true) if options[:dryrun]
|
209
|
+
push_command.set_remote(remote)
|
210
|
+
push_command.set_ref_specs(refs)
|
211
|
+
if options[:username]
|
212
|
+
push_command.set_credentials_provider(UsernamePasswordCredentialsProvider.new(options[:username], options[:password]))
|
213
|
+
end
|
214
|
+
push_command.call
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def pull(options = {})
|
219
|
+
pull_command = @jgit.pull
|
220
|
+
pull_command.set_dry_run(true) if options[:dryrun]
|
221
|
+
pull_command.set_rebase(options[:rebase]) if options[:rebase]
|
222
|
+
if options[:username]
|
223
|
+
pull_command.set_credentials_provider(UsernamePasswordCredentialsProvider.new(options[:username], options[:password]))
|
224
|
+
end
|
225
|
+
pull_command.call
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
Binary file
|
Binary file
|
data/lib/repo.rb
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
module RJGit
|
2
|
+
|
3
|
+
import 'org.eclipse.jgit.lib.Repository'
|
4
|
+
import 'org.eclipse.jgit.lib.RepositoryBuilder'
|
5
|
+
import 'org.eclipse.jgit.storage.file.FileRepository'
|
6
|
+
import 'org.eclipse.jgit.treewalk.TreeWalk'
|
7
|
+
import 'org.eclipse.jgit.treewalk.filter.PathFilter'
|
8
|
+
import 'org.eclipse.jgit.lib.Constants'
|
9
|
+
import 'org.eclipse.jgit.lib.RefWriter'
|
10
|
+
import 'java.io.IOException'
|
11
|
+
|
12
|
+
# Implementation of RefWriter for local files. This class is able to generate and write the $GIT_DIR/info/refs. For use in Repo::update_server_info.
|
13
|
+
class LocalRefWriter < RefWriter
|
14
|
+
attr_accessor :path
|
15
|
+
|
16
|
+
def initialize(refs, path)
|
17
|
+
super(refs)
|
18
|
+
@path = path
|
19
|
+
end
|
20
|
+
|
21
|
+
def writeFile(file, content)
|
22
|
+
file = File.join(@path, file)
|
23
|
+
begin
|
24
|
+
f = File.open(file, "w")
|
25
|
+
f.write String.from_java_bytes(content)
|
26
|
+
f.close
|
27
|
+
rescue
|
28
|
+
raise IOException.new # JGit API requires RefWriter.writeFile to throw IOException
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
class Repo
|
35
|
+
|
36
|
+
attr_accessor :git
|
37
|
+
attr_accessor :jrepo
|
38
|
+
attr_accessor :path
|
39
|
+
|
40
|
+
PACK_LIST = 'objects/info/packs'
|
41
|
+
|
42
|
+
RJGit.delegate_to(Repository, :@jrepo)
|
43
|
+
|
44
|
+
def initialize(path, options = {})
|
45
|
+
epath = File.expand_path(path)
|
46
|
+
|
47
|
+
bare = false
|
48
|
+
if File.exist?(File.join(epath, '/.git'))
|
49
|
+
bare = false
|
50
|
+
elsif File.exist?(epath) || options[:bare]
|
51
|
+
bare = true
|
52
|
+
end
|
53
|
+
|
54
|
+
@path = bare ? epath : File.join(epath, '/.git')
|
55
|
+
@config = RJGit::Configuration.new(File.join(@path, 'config'))
|
56
|
+
repo_path = java.io.File.new(@path)
|
57
|
+
@jrepo = bare ? RepositoryBuilder.new().set_bare.set_git_dir(repo_path).build() : RepositoryBuilder.new().set_git_dir(repo_path).build()
|
58
|
+
@jrepo.create(bare) if options[:create]
|
59
|
+
@git = RubyGit.new(@jrepo)
|
60
|
+
end
|
61
|
+
|
62
|
+
def bare?
|
63
|
+
@jrepo.is_bare
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.create(path, options = {:bare => false})
|
67
|
+
options[:create] = true
|
68
|
+
Repo.new(path, options)
|
69
|
+
end
|
70
|
+
|
71
|
+
def commits(ref="master", limit=100)
|
72
|
+
options = { :limit => limit }
|
73
|
+
Commit.find_all(@jrepo, ref, options)
|
74
|
+
end
|
75
|
+
|
76
|
+
def config
|
77
|
+
@config.load
|
78
|
+
end
|
79
|
+
|
80
|
+
def branch
|
81
|
+
@jrepo.get_full_branch
|
82
|
+
end
|
83
|
+
|
84
|
+
def branches
|
85
|
+
return @git.branch_list
|
86
|
+
end
|
87
|
+
|
88
|
+
def create_branch(name)
|
89
|
+
@git.create_branch(name)
|
90
|
+
end
|
91
|
+
|
92
|
+
def delete_branch(name)
|
93
|
+
@git.delete_branch(name)
|
94
|
+
end
|
95
|
+
|
96
|
+
def rename_branch(old_name, new_name)
|
97
|
+
@git.rename_branch(old_name, new_name)
|
98
|
+
end
|
99
|
+
|
100
|
+
def checkout(branch_name, options = {})
|
101
|
+
@git.checkout(branch_name, options)
|
102
|
+
end
|
103
|
+
alias_method :switch, :checkout
|
104
|
+
|
105
|
+
|
106
|
+
def tags(lightweight = false)
|
107
|
+
jtags = @jrepo.get_tags.to_hash
|
108
|
+
if lightweight
|
109
|
+
jtags.each_with_object( Hash.new ) do |(key, value), hash|
|
110
|
+
hash[key] = ObjectId.to_string(value.get_object_id)
|
111
|
+
end
|
112
|
+
else
|
113
|
+
tags = Hash.new
|
114
|
+
jtags.each do |key, value|
|
115
|
+
jtag = @git.resolve_tag(value)
|
116
|
+
if jtag
|
117
|
+
tag = Tag.new(jtag)
|
118
|
+
tags[key] = tag
|
119
|
+
end
|
120
|
+
end
|
121
|
+
tags
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def add(file_pattern)
|
126
|
+
@git.add(file_pattern)
|
127
|
+
end
|
128
|
+
|
129
|
+
def remove(file_pattern)
|
130
|
+
@git.remove(file_pattern)
|
131
|
+
end
|
132
|
+
|
133
|
+
def commit(message)
|
134
|
+
@git.commit(message)
|
135
|
+
end
|
136
|
+
|
137
|
+
def clean(options = {})
|
138
|
+
@git.clean(options)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Convenience method to retrieve a Blob by name
|
142
|
+
def blob(file_path)
|
143
|
+
Blob.find_blob(@jrepo, file_path)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Convenience method to retrieve a Tree by name
|
147
|
+
def tree(file_path)
|
148
|
+
Tree.find_tree(@jrepo, file_path)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Update the info files required for fetching files over the dump-HTTP protocol
|
152
|
+
def update_server_info
|
153
|
+
# First update the $GIT_DIR/refs/info file
|
154
|
+
refs = @jrepo.get_all_refs # Note: JGit will include directories under $GIT_DIR/refs/heads that start with a '.' in its search for refs. Filter these out in LocalRefWriter?
|
155
|
+
writer = LocalRefWriter.new(refs, @path)
|
156
|
+
writer.write_info_refs
|
157
|
+
|
158
|
+
# Now update the $GIT_OBJECT_DIRECTORY/info/packs file
|
159
|
+
f = File.new(File.join(@path, PACK_LIST), "w")
|
160
|
+
@jrepo.get_object_database.get_packs.each do |pack|
|
161
|
+
f.write "P " + pack.get_pack_file.get_name + "\n"
|
162
|
+
end
|
163
|
+
f.write "\n"
|
164
|
+
f.close
|
165
|
+
|
166
|
+
return true
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
data/lib/rjgit.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
module RJGit
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'java'
|
5
|
+
Dir["#{File.dirname(__FILE__)}/java/jars/*.jar"].each { |jar| require jar }
|
6
|
+
rescue LoadError
|
7
|
+
raise "You need to be running JRuby to use this gem."
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.version
|
11
|
+
VERSION
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'stringio'
|
15
|
+
# gem requires
|
16
|
+
require 'mime/types'
|
17
|
+
# require helpers first because RJGit#delegate_to is needed
|
18
|
+
require "#{File.dirname(__FILE__)}/rjgit_helpers.rb"
|
19
|
+
# require everything else
|
20
|
+
begin
|
21
|
+
Dir["#{File.dirname(__FILE__)}/*.rb"].each do |file|
|
22
|
+
require file
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
import 'org.eclipse.jgit.lib.ObjectId'
|
27
|
+
|
28
|
+
class Porcelain
|
29
|
+
|
30
|
+
import 'org.eclipse.jgit.api.AddCommand'
|
31
|
+
import 'org.eclipse.jgit.api.CommitCommand'
|
32
|
+
import 'org.eclipse.jgit.api.BlameCommand'
|
33
|
+
import 'org.eclipse.jgit.blame.BlameGenerator'
|
34
|
+
import 'org.eclipse.jgit.blame.BlameResult'
|
35
|
+
|
36
|
+
# http://wiki.eclipse.org/JGit/User_Guide#Porcelain_API
|
37
|
+
def self.add(repository, file_pattern)
|
38
|
+
repository.add(file_pattern)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.commit(repository, message="")
|
42
|
+
repository.commit(message)
|
43
|
+
end
|
44
|
+
|
45
|
+
# http://dev.eclipse.org/mhonarc/lists/jgit-dev/msg00558.html
|
46
|
+
def self.cat_file(repository, object)
|
47
|
+
bytes = repository.open(object.id).get_bytes
|
48
|
+
return bytes.to_a.pack('c*').force_encoding('UTF-8')
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.ls_tree(repository, tree=nil, options={})
|
52
|
+
options = {:recursive => false, :print => false, :io => $stdout, :branch => Constants::HEAD}.merge(options)
|
53
|
+
jrepo = RJGit.repository_type(repository)
|
54
|
+
return nil unless jrepo
|
55
|
+
if tree
|
56
|
+
jtree = RJGit.tree_type(tree)
|
57
|
+
else
|
58
|
+
last_commit_hash = jrepo.resolve(options[:branch])
|
59
|
+
return nil unless last_commit_hash
|
60
|
+
walk = RevWalk.new(jrepo)
|
61
|
+
jcommit = walk.parse_commit(last_commit_hash)
|
62
|
+
jtree = jcommit.get_tree
|
63
|
+
end
|
64
|
+
treewalk = TreeWalk.new(jrepo)
|
65
|
+
treewalk.set_recursive(options[:recursive])
|
66
|
+
treewalk.add_tree(jtree)
|
67
|
+
entries = []
|
68
|
+
while treewalk.next
|
69
|
+
entry = {}
|
70
|
+
mode = treewalk.get_file_mode(0)
|
71
|
+
entry[:mode] = mode.get_bits
|
72
|
+
entry[:type] = Constants.type_string(mode.get_object_type)
|
73
|
+
entry[:id] = treewalk.get_object_id(0).name
|
74
|
+
entry[:path] = treewalk.get_path_string
|
75
|
+
entries << entry
|
76
|
+
end
|
77
|
+
options[:io].puts RJGit.stringify(entries) if options[:print]
|
78
|
+
entries
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.blame(repository, file_path, options={})
|
82
|
+
options = {:print => false, :io => $stdout}.merge(options)
|
83
|
+
jrepo = RJGit.repository_type(repository)
|
84
|
+
return nil unless jrepo
|
85
|
+
|
86
|
+
blame_command = BlameCommand.new(jrepo)
|
87
|
+
blame_command.set_file_path(file_path)
|
88
|
+
result = blame_command.call
|
89
|
+
content = result.get_result_contents
|
90
|
+
blame = []
|
91
|
+
for index in (0..content.size - 1) do
|
92
|
+
blameline = {}
|
93
|
+
blameline[:actor] = Actor.new(result.get_source_author(index))
|
94
|
+
blameline[:line] = result.get_source_line(index)
|
95
|
+
blameline[:commit] = Commit.new(result.get_source_commit(index))
|
96
|
+
blameline[:line] = content.get_string(index)
|
97
|
+
blame << blameline
|
98
|
+
end
|
99
|
+
options[:io].puts RJGit.stringify(blame) if options[:print]
|
100
|
+
return blame
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.diff(repository, options = {})
|
104
|
+
options = {:namestatus => false}.merge(options)
|
105
|
+
git = repository.git.jgit
|
106
|
+
diff_command = git.diff
|
107
|
+
diff_command.set_old_tree(old_tree) if options[:old_tree]
|
108
|
+
diff_command.set_new_tree(new_tree) if options[:new_tree]
|
109
|
+
diff_command.set_path_filter(PathFilter.create(file_path)) if options[:file_path]
|
110
|
+
diff_command.set_show_name_and_status_only(true) if options[:namestatus]
|
111
|
+
diff_command.set_cached(true) if options[:cached]
|
112
|
+
diff_entries = diff_command.call
|
113
|
+
diff_entries = diff_entries.to_array.to_ary
|
114
|
+
diff_entries = RJGit.convert_diff_entries(diff_entries)
|
115
|
+
diff_entries
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module RJGit
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
extend Forwardable
|
5
|
+
|
6
|
+
def self.underscore(camel_cased_word)
|
7
|
+
camel_cased_word.to_s.gsub(/::/, '/').
|
8
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
9
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
10
|
+
tr("-", "_").
|
11
|
+
downcase
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.delegate_to(klass, delegate_name)
|
15
|
+
java_methods = klass.java_class.declared_instance_methods.map{ |method| method.name.to_sym }
|
16
|
+
def_delegators delegate_name, *java_methods
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.get_file_mode(repository, path, jtree)
|
20
|
+
treewalk = TreeWalk.forPath(repository, path, jtree)
|
21
|
+
return treewalk.get_file_mode(0).get_bits
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.stringify(entries)
|
25
|
+
str = ""
|
26
|
+
entries.each do |entry|
|
27
|
+
line = entry.values.join("\t")
|
28
|
+
str = "#{str}#{line}\n"
|
29
|
+
end
|
30
|
+
str
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.convert_diff_entries(entries)
|
34
|
+
entries.map do |diff_entry|
|
35
|
+
RJGit. diff_entry_to_hash(diff_entry)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.diff_entry_to_hash(diff_entry)
|
40
|
+
entry = {}
|
41
|
+
entry[:changetype] = diff_entry.get_change_type.to_string
|
42
|
+
entry[:oldpath] = diff_entry.get_old_path
|
43
|
+
entry[:newpath] = diff_entry.get_new_path
|
44
|
+
entry[:oldmode] = diff_entry.get_old_mode.get_bits
|
45
|
+
entry[:newmode] = diff_entry.get_new_mode.get_bits
|
46
|
+
entry[:score] = diff_entry.get_score
|
47
|
+
entry[:oldid] = diff_entry.get_old_id.name
|
48
|
+
entry[:newid] = diff_entry.get_new_id.name
|
49
|
+
entry
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def self.repository_type(repository)
|
54
|
+
repo = case repository
|
55
|
+
when Repo then repository.jrepo
|
56
|
+
when org.eclipse.jgit.lib.Repository then repository
|
57
|
+
else nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.actor_type(actor)
|
62
|
+
person_ident = case actor
|
63
|
+
when Actor then actor.person_ident
|
64
|
+
when org.eclipse.jgit.lib.PersonIdent then actor
|
65
|
+
else nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.tree_type(tree)
|
70
|
+
treeobj = case tree
|
71
|
+
when Tree then tree.jtree
|
72
|
+
when org.eclipse.jgit.revwalk.RevTree then tree
|
73
|
+
else nil
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
data/lib/tag.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module RJGit
|
2
|
+
|
3
|
+
import 'org.eclipse.jgit.revwalk'
|
4
|
+
import 'org.eclipse.jgit.revwalk.RevTag'
|
5
|
+
|
6
|
+
class Tag
|
7
|
+
|
8
|
+
attr_reader :id, :jtag
|
9
|
+
RJGit.delegate_to(RevTag, :@jtag)
|
10
|
+
|
11
|
+
def initialize(jtag)
|
12
|
+
@jtag = jtag
|
13
|
+
@id = ObjectId.to_string(jtag.get_id)
|
14
|
+
end
|
15
|
+
|
16
|
+
def full_message
|
17
|
+
@full_message ||= @jtag.get_full_message
|
18
|
+
end
|
19
|
+
|
20
|
+
def short_message
|
21
|
+
@short_message ||= @jtag.get_short_message
|
22
|
+
end
|
23
|
+
|
24
|
+
def actor
|
25
|
+
@actor ||= Actor.new(@jtag.get_tagger_ident)
|
26
|
+
end
|
27
|
+
|
28
|
+
def name
|
29
|
+
@name ||= @jtag.get_tag_name
|
30
|
+
end
|
31
|
+
|
32
|
+
def type
|
33
|
+
@type ||= @jtag.get_type
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
data/lib/transport.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
module RJGit
|
2
|
+
|
3
|
+
import "org.eclipse.jgit.transport.ReceivePack"
|
4
|
+
import "org.eclipse.jgit.transport.UploadPack"
|
5
|
+
import "org.eclipse.jgit.transport.PacketLineOut"
|
6
|
+
import "org.eclipse.jgit.transport.RefAdvertiser$PacketLineOutRefAdvertiser"
|
7
|
+
import "java.io.ByteArrayInputStream"
|
8
|
+
import "java.io.ByteArrayOutputStream"
|
9
|
+
|
10
|
+
class RJGitPack
|
11
|
+
attr_accessor :jpack, :jrepo, :bidirectional
|
12
|
+
|
13
|
+
def initialize(repository, bidirectional = false)
|
14
|
+
@jrepo = RJGit.repository_type(repository)
|
15
|
+
@bidirectional = bidirectional
|
16
|
+
end
|
17
|
+
|
18
|
+
def init_buffers(client_msg)
|
19
|
+
return ByteArrayInputStream.new(client_msg.to_java_bytes), ByteArrayOutputStream.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def advertise_refs
|
23
|
+
out_stream = ByteArrayOutputStream.new
|
24
|
+
pck_out = PacketLineOut.new(out_stream)
|
25
|
+
advertiser = PacketLineOutRefAdvertiser.new(pck_out)
|
26
|
+
@jpack.sendAdvertisedRefs(advertiser)
|
27
|
+
return out_stream.to_string
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class RJGitReceivePack < RJGitPack
|
32
|
+
|
33
|
+
def initialize(repository, bidirectional = false)
|
34
|
+
super
|
35
|
+
@jpack = ReceivePack.new(@jrepo)
|
36
|
+
end
|
37
|
+
|
38
|
+
def process(client_msg)
|
39
|
+
self.receive(client_msg)
|
40
|
+
end
|
41
|
+
|
42
|
+
def receive(client_msg)
|
43
|
+
in_stream, out_stream = init_buffers(client_msg)
|
44
|
+
@jpack.set_bi_directional_pipe(@bidirectional)
|
45
|
+
begin
|
46
|
+
@jpack.receive(in_stream, out_stream, nil)
|
47
|
+
rescue Java::OrgEclipseJgitErrors::InvalidObjectIdException, Java::JavaIo::IOException => e
|
48
|
+
return nil, e
|
49
|
+
end
|
50
|
+
return ByteArrayInputStream.new(out_stream.to_byte_array).to_io, nil
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
class RJGitUploadPack < RJGitPack
|
56
|
+
|
57
|
+
def initialize(repository, bidirectional = false)
|
58
|
+
super
|
59
|
+
@jpack = UploadPack.new(@jrepo)
|
60
|
+
end
|
61
|
+
|
62
|
+
def process(client_msg)
|
63
|
+
self.upload(client_msg)
|
64
|
+
end
|
65
|
+
|
66
|
+
def upload(client_msg)
|
67
|
+
in_stream, out_stream = init_buffers(client_msg)
|
68
|
+
@jpack.set_bi_directional_pipe(@bidirectional)
|
69
|
+
begin
|
70
|
+
@jpack.upload(in_stream, out_stream, nil)
|
71
|
+
rescue Java::OrgEclipseJgitErrors::InvalidObjectIdException, Java::OrgEclipseJgitTransport::UploadPackInternalServerErrorException, Java::JavaIo::IOException => e
|
72
|
+
return nil, e
|
73
|
+
end
|
74
|
+
return ByteArrayInputStream.new(out_stream.to_byte_array).to_io, nil
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
data/lib/tree.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module RJGit
|
2
|
+
|
3
|
+
import 'org.eclipse.jgit.revwalk'
|
4
|
+
import 'org.eclipse.jgit.revwalk.RevTree'
|
5
|
+
|
6
|
+
class Tree
|
7
|
+
|
8
|
+
attr_reader :contents, :id, :mode, :name, :repo, :jtree
|
9
|
+
RJGit.delegate_to(RevTree, :@jtree)
|
10
|
+
|
11
|
+
def initialize(repository, mode, path, jtree)
|
12
|
+
@repo = repository
|
13
|
+
@mode = mode
|
14
|
+
@path = path
|
15
|
+
@name = File.basename(path)
|
16
|
+
@jtree = jtree
|
17
|
+
@id = ObjectId.to_string(jtree.get_id)
|
18
|
+
end
|
19
|
+
|
20
|
+
def data
|
21
|
+
strio = StringIO.new
|
22
|
+
RJGit::Porcelain.ls_tree(@repo, @jtree, options={:print => true, :io => strio})
|
23
|
+
strio.string
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.find_tree(repository, file_path, branch=Constants::HEAD)
|
27
|
+
jrepo = RJGit.repository_type(repository)
|
28
|
+
return nil if jrepo.nil?
|
29
|
+
last_commit_hash = jrepo.resolve(branch)
|
30
|
+
return nil if last_commit_hash.nil?
|
31
|
+
|
32
|
+
walk = RevWalk.new(jrepo)
|
33
|
+
commit = walk.parse_commit(last_commit_hash)
|
34
|
+
treewalk = TreeWalk.new(jrepo)
|
35
|
+
jtree = commit.get_tree
|
36
|
+
treewalk.add_tree(jtree)
|
37
|
+
treewalk.set_filter(PathFilter.create(file_path))
|
38
|
+
if treewalk.next
|
39
|
+
jsubtree = walk.lookup_tree(treewalk.object_id(0))
|
40
|
+
if jsubtree
|
41
|
+
mode = RJGit.get_file_mode(jrepo, file_path, jtree)
|
42
|
+
Tree.new(jrepo, mode, file_path, jsubtree)
|
43
|
+
end
|
44
|
+
else
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
data/lib/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rjgit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Maarten Engelen
|
9
|
+
- Bart Kamphorst
|
10
|
+
- Dawa Ometto
|
11
|
+
- Arlette van Wissen
|
12
|
+
- Steven Woudenberg
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
date: 2013-04-03 00:00:00.000000000 Z
|
17
|
+
dependencies:
|
18
|
+
- !ruby/object:Gem::Dependency
|
19
|
+
name: mime-types
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - "~>"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: '1.15'
|
25
|
+
none: false
|
26
|
+
requirement: !ruby/object:Gem::Requirement
|
27
|
+
requirements:
|
28
|
+
- - "~>"
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '1.15'
|
31
|
+
none: false
|
32
|
+
prerelease: false
|
33
|
+
type: :runtime
|
34
|
+
description: JRuby wrapper around the JGit library for manipulating git repositories in code.
|
35
|
+
email: repotag-dev@googlegroups.com
|
36
|
+
executables: []
|
37
|
+
extensions: []
|
38
|
+
extra_rdoc_files:
|
39
|
+
- README.md
|
40
|
+
files:
|
41
|
+
- lib/actor.rb
|
42
|
+
- lib/blob.rb
|
43
|
+
- lib/commit.rb
|
44
|
+
- lib/config.rb
|
45
|
+
- lib/constants.rb
|
46
|
+
- lib/git.rb
|
47
|
+
- lib/repo.rb
|
48
|
+
- lib/rjgit.rb
|
49
|
+
- lib/rjgit_helpers.rb
|
50
|
+
- lib/tag.rb
|
51
|
+
- lib/transport.rb
|
52
|
+
- lib/tree.rb
|
53
|
+
- lib/version.rb
|
54
|
+
- README.md
|
55
|
+
- LICENSE
|
56
|
+
- Gemfile
|
57
|
+
- lib/java/jars/jsch-0.1.49.jar
|
58
|
+
- lib/java/jars/org.eclipse.jgit-2.3.1.201302201838-r.jar
|
59
|
+
homepage: https://github.com/repotag/rjgit
|
60
|
+
licenses: []
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options:
|
63
|
+
- "--charset=UTF-8"
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: !binary |-
|
71
|
+
MA==
|
72
|
+
none: false
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: !binary |-
|
78
|
+
MA==
|
79
|
+
none: false
|
80
|
+
requirements: []
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.8.24
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: JRuby wrapper around the JGit library.
|
86
|
+
test_files: []
|