rup 0.3.2
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/LICENSE +13 -0
- data/README +42 -0
- data/Rakefile +71 -0
- data/TODO +9 -0
- data/bin/rup +358 -0
- data/lib/status.rb +3 -0
- metadata +62 -0
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright (C) 2009 Otype.net
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
== Rup
|
2
|
+
|
3
|
+
=== Install
|
4
|
+
Simply copy "<project_directory>/lib/rup" to either
|
5
|
+
|
6
|
+
/usr/bin
|
7
|
+
/usr/local/bin
|
8
|
+
/opt/local/bin
|
9
|
+
|
10
|
+
or any other bin directory that is available via your
|
11
|
+
PATH variable.
|
12
|
+
|
13
|
+
Make sure that "rup" has execute permissions:
|
14
|
+
|
15
|
+
$ chmod u+x <rup_dir>/rup
|
16
|
+
|
17
|
+
=== Required
|
18
|
+
RUP works with Subversion, GIT and Repo.
|
19
|
+
|
20
|
+
It requires all these tools to be available via PATH variable.
|
21
|
+
|
22
|
+
=== Usage
|
23
|
+
|
24
|
+
Simply run "rup -h" to see the help page.
|
25
|
+
|
26
|
+
Adding a repository location to rup configuration:
|
27
|
+
|
28
|
+
$ rup -a <repo_dir>
|
29
|
+
|
30
|
+
List all repositories under rup control:
|
31
|
+
|
32
|
+
$ rup -l
|
33
|
+
|
34
|
+
Update all repositories in rup:
|
35
|
+
|
36
|
+
$ rup -u
|
37
|
+
|
38
|
+
See "rup -h" for more options.
|
39
|
+
|
40
|
+
== Copyright
|
41
|
+
|
42
|
+
Copyright (c) 2009 Hans-Gunther Schmidt. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/clean'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
require 'rake/testtask'
|
7
|
+
|
8
|
+
|
9
|
+
spec = Gem::Specification.new do |s|
|
10
|
+
s.name = 'rup'
|
11
|
+
s.version = File.open("VERSION", 'r') { |f| f.read.strip }
|
12
|
+
s.homepage = 'http://rubyforge.org/projects/rup/'
|
13
|
+
s.rubyforge_project = s.name
|
14
|
+
s.has_rdoc = true
|
15
|
+
s.extra_rdoc_files = ['README', 'LICENSE', 'TODO']
|
16
|
+
s.description = 'Manage multiple repositories at different locations from common SCM tool type as SVN, GIT, REPO with one simple CLI tool.'
|
17
|
+
s.summary = 'SCM Repository manager in Ruby'
|
18
|
+
s.author = 'Hans-Gunther Schmidt'
|
19
|
+
s.email = 'hans@otype.de'
|
20
|
+
s.executables = ['rup']
|
21
|
+
s.files = %w(LICENSE README TODO Rakefile) + Dir.glob("{bin,lib,spec}/**/*")
|
22
|
+
s.require_path = "lib"
|
23
|
+
s.bindir = "bin"
|
24
|
+
end
|
25
|
+
|
26
|
+
begin
|
27
|
+
require 'jeweler'
|
28
|
+
Jeweler::Tasks.new do |gem|
|
29
|
+
gem.name = spec.name
|
30
|
+
gem.summary = spec.summary
|
31
|
+
gem.description = spec.description
|
32
|
+
gem.email = spec.email
|
33
|
+
gem.rubyforge_project = spec.name
|
34
|
+
gem.authors = [spec.author]
|
35
|
+
gem.extra_rdoc_files = spec.extra_rdoc_files
|
36
|
+
gem.executables = ['rup']
|
37
|
+
gem.homepage = spec.homepage
|
38
|
+
#gem.rubyforge_project = 'http://rubyforge.org/projects/rup/'
|
39
|
+
#gem.homepage = "http://github.com/otype/rup"
|
40
|
+
#gem.add_development_dependency "thoughtbot-shoulda"
|
41
|
+
|
42
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
43
|
+
end
|
44
|
+
|
45
|
+
Jeweler::GemcutterTasks.new
|
46
|
+
|
47
|
+
Jeweler::RubyforgeTasks.new do |rubyforge|
|
48
|
+
rubyforge.doc_task = "rdoc"
|
49
|
+
end
|
50
|
+
rescue LoadError
|
51
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
52
|
+
end
|
53
|
+
|
54
|
+
Rake::GemPackageTask.new(spec) do |p|
|
55
|
+
p.gem_spec = spec
|
56
|
+
p.need_tar = true
|
57
|
+
p.need_zip = true
|
58
|
+
end
|
59
|
+
|
60
|
+
Rake::RDocTask.new do |rdoc|
|
61
|
+
files =['README', 'LICENSE', 'TODO', 'lib/**/*.rb']
|
62
|
+
rdoc.rdoc_files.add(files)
|
63
|
+
rdoc.main = "README" # page to start on
|
64
|
+
rdoc.title = "Rup Docs"
|
65
|
+
rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
|
66
|
+
rdoc.options << '--line-numbers'
|
67
|
+
end
|
68
|
+
|
69
|
+
Rake::TestTask.new do |t|
|
70
|
+
t.test_files = FileList['test/**/*.rb']
|
71
|
+
end
|
data/TODO
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
= RUP TODO's
|
2
|
+
|
3
|
+
== Mon May 11 10:17:40 CEST 2009
|
4
|
+
- Make nicer output of 'rup -l'
|
5
|
+
- Create configuration menu for setting up SCM tool paths
|
6
|
+
(instead of getting paths from environment variable PATH)
|
7
|
+
- Add Rake task for installation
|
8
|
+
- Enable removal of RUP repositories via numbers (each reference receives a number)
|
9
|
+
-> no need to enter full repository path on removal
|
data/bin/rup
ADDED
@@ -0,0 +1,358 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Copyright (C) 2009 Otype.net
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
|
18
|
+
# Required for OptParser class
|
19
|
+
require 'optparse'
|
20
|
+
require 'ostruct'
|
21
|
+
|
22
|
+
|
23
|
+
#
|
24
|
+
# GLOBALS
|
25
|
+
#
|
26
|
+
$COMMAND_NAME = "rup"
|
27
|
+
$VERSION = "0.3.1"
|
28
|
+
|
29
|
+
# Required for LibConfig
|
30
|
+
$CONFIGDIR = ENV['HOME'] + "/.rup"
|
31
|
+
$CONFIGFILE = $CONFIGDIR + "/repositories.cfg"
|
32
|
+
|
33
|
+
##############################################################
|
34
|
+
# SCM Hashes
|
35
|
+
#
|
36
|
+
# All SCM tools including their parameters are configured
|
37
|
+
# here. Make sure that these are correct!
|
38
|
+
#
|
39
|
+
##############################################################
|
40
|
+
|
41
|
+
$SVN = {
|
42
|
+
'COMMAND' => `which svn`.chomp,
|
43
|
+
'ADD' => "add",
|
44
|
+
'CHECKOUT' => "checkout",
|
45
|
+
'COMMIT' => "commit",
|
46
|
+
'COMMIT_COMM' => "-m",
|
47
|
+
'INFO' => "info",
|
48
|
+
'INIT' => "",
|
49
|
+
'LOG' => "log",
|
50
|
+
'MOVE' => "move",
|
51
|
+
'REMOVE' => "remove",
|
52
|
+
'STATUS' => "status",
|
53
|
+
'UPDATE' => "up"
|
54
|
+
}
|
55
|
+
|
56
|
+
$GIT = {
|
57
|
+
'COMMAND' => `which git`.chomp,
|
58
|
+
'ADD' => "add",
|
59
|
+
'CHECKOUT' => "clone",
|
60
|
+
'COMMIT' => "commit",
|
61
|
+
'COMMIT_COMM' => "-a",
|
62
|
+
'INFO' => "info",
|
63
|
+
'INIT' => "init",
|
64
|
+
'LOG' => "log",
|
65
|
+
'MOVE' => "move",
|
66
|
+
'REMOVE' => "rm",
|
67
|
+
'STATUS' => "status",
|
68
|
+
'UPDATE' => "pull"
|
69
|
+
}
|
70
|
+
|
71
|
+
$REPO = {
|
72
|
+
'COMMAND' => `which repo`.chomp,
|
73
|
+
'ADD' => "",
|
74
|
+
'CHECKOUT' => "",
|
75
|
+
'COMMIT' => "",
|
76
|
+
'COMMIT_COMM' => "",
|
77
|
+
'INFO' => "",
|
78
|
+
'INIT' => "init",
|
79
|
+
'LOG' => "",
|
80
|
+
'MOVE' => "",
|
81
|
+
'REMOVE' => "",
|
82
|
+
'STATUS' => "status",
|
83
|
+
'UPDATE' => "sync"
|
84
|
+
}
|
85
|
+
|
86
|
+
##############################################################
|
87
|
+
# LibConfig
|
88
|
+
#
|
89
|
+
# Manages the configuration and triggers all SCM commands
|
90
|
+
# (high-level interface)
|
91
|
+
#
|
92
|
+
##############################################################
|
93
|
+
|
94
|
+
class LibConfig
|
95
|
+
|
96
|
+
def self.add_repo(path)
|
97
|
+
init
|
98
|
+
return "Not a valid SCM type." if LibSCM.scm_type(path).nil?
|
99
|
+
return "Repo already under RUP control." if repo_exist?(clean_path(path))
|
100
|
+
conffile = File.open($CONFIGFILE, "a+")
|
101
|
+
conffile.puts(clean_path(path))
|
102
|
+
conffile.close
|
103
|
+
return "[Added repository => \'#{path}\']"
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.remove_repo(path)
|
107
|
+
init
|
108
|
+
return "Repository is not under RUP control." if not repo_exist?(path)
|
109
|
+
|
110
|
+
oldrepos = (File.open($CONFIGFILE, "r")).readlines
|
111
|
+
arr = Array.new
|
112
|
+
oldrepos.each { |v| arr << v.chomp if not v.eql?("#{path}\n")}
|
113
|
+
|
114
|
+
tmpcfg = "#{$CONFIGDIR}/_repos.tmp"
|
115
|
+
newrepos = File.new(tmpcfg, "w", 0600)
|
116
|
+
arr.each { |v| newrepos.puts(v) }
|
117
|
+
newrepos.close
|
118
|
+
File.rename(tmpcfg, $CONFIGFILE)
|
119
|
+
return "[Removed repository => \'#{path}\']"
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.import_parent(path)
|
123
|
+
return "No directory." if not File.directory?(path)
|
124
|
+
dirs = Dir.entries(path)
|
125
|
+
only_valid_directories(dirs)
|
126
|
+
dirs = dirs.map { |v| path + "/" + v }
|
127
|
+
|
128
|
+
repos = Array.new
|
129
|
+
skipped = Array.new
|
130
|
+
dirs.each { |d| LibSCM.valid_scm?(d) ? (repos << d) : (skipped << d) }
|
131
|
+
repos.each { |r| add_repo(r) }
|
132
|
+
|
133
|
+
"[Parent paths imported ]" + "\n\n[ Skipped ]\n" + skipped.join("\n")
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.list_repos
|
137
|
+
init
|
138
|
+
repos = (File.open($CONFIGFILE, "r")).readlines
|
139
|
+
ans = String.new
|
140
|
+
repos.each { |elem| ans += elem }
|
141
|
+
ans.empty? ? "No repositories under RUP control." : ans
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def self.only_valid_directories(dirs)
|
147
|
+
dirs.delete_if { |v| v.eql?(".") or v.eql?("..") or v.eql?(".DS_Store") }
|
148
|
+
end
|
149
|
+
|
150
|
+
def self.clean_path(path)
|
151
|
+
(File.directory?(path) and not path[-1,1].eql?("/")) ? path + "/" : path
|
152
|
+
end
|
153
|
+
|
154
|
+
def self.repo_exist?(repo)
|
155
|
+
repos = (File.open($CONFIGFILE, "r")).readlines
|
156
|
+
repos.include?("#{repo}\n")
|
157
|
+
end
|
158
|
+
|
159
|
+
def self.init
|
160
|
+
create_config_dir
|
161
|
+
create_config_file
|
162
|
+
end
|
163
|
+
|
164
|
+
def self.create_config_dir
|
165
|
+
Dir.mkdir($CONFIGDIR) if not File.exist?($CONFIGDIR)
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.create_config_file
|
169
|
+
(File.open($CONFIGFILE, "a+", 0600)).close if not File.exist?($CONFIGFILE)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
##############################################################
|
174
|
+
# LibSCM
|
175
|
+
#
|
176
|
+
# Interface to the SCM tools on OS-level (low-level interface)
|
177
|
+
#
|
178
|
+
##############################################################
|
179
|
+
class LibSCM
|
180
|
+
|
181
|
+
def self.repo_status
|
182
|
+
repos = LibConfig.list_repos.to_a
|
183
|
+
repos.each do |r|
|
184
|
+
puts "[ Status for repository => \'#{r.chomp}\']"
|
185
|
+
puts status(r.chomp)
|
186
|
+
puts "\n"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def self.update_repos
|
191
|
+
repos = LibConfig.list_repos.to_a
|
192
|
+
repos.each do |r|
|
193
|
+
puts "[ Updating repository => \'#{r.chomp}\']"
|
194
|
+
puts update(r.chomp)
|
195
|
+
puts "\n"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def self.scm_type(repopath)
|
200
|
+
scmtype = "SVN" if File.exist?(repopath + "/.svn")
|
201
|
+
scmtype = "GIT" if File.exist?(repopath + "/.git")
|
202
|
+
scmtype = "REPO" if File.exist?(repopath + "/.repo")
|
203
|
+
scmtype
|
204
|
+
end
|
205
|
+
|
206
|
+
def self.valid_scm?(repopath)
|
207
|
+
not scm_type(repopath).nil?
|
208
|
+
end
|
209
|
+
|
210
|
+
private
|
211
|
+
|
212
|
+
def self.status(entity)
|
213
|
+
scm = load_scm(entity)
|
214
|
+
Dir.chdir(entity)
|
215
|
+
%x{#{scm['COMMAND']} #{scm['STATUS']} }
|
216
|
+
end
|
217
|
+
|
218
|
+
def self.update(entity)
|
219
|
+
scm = load_scm(entity)
|
220
|
+
Dir.chdir(entity)
|
221
|
+
%x{#{scm['COMMAND']} #{scm['UPDATE']} }
|
222
|
+
end
|
223
|
+
|
224
|
+
def self.load_scm(entity)
|
225
|
+
load_hash(scm_type(entity))
|
226
|
+
end
|
227
|
+
|
228
|
+
def self.load_hash(scmtype)
|
229
|
+
case scmtype
|
230
|
+
when /GIT/
|
231
|
+
$GIT
|
232
|
+
when /SVN/
|
233
|
+
$SVN
|
234
|
+
when /REPO/
|
235
|
+
$REPO
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
##############################################################
|
241
|
+
# OptParser
|
242
|
+
#
|
243
|
+
# Option parser: all shell command options which can be
|
244
|
+
# triggered.
|
245
|
+
#
|
246
|
+
##############################################################
|
247
|
+
class OptParser
|
248
|
+
def self.parse(args)
|
249
|
+
options = OpenStruct.new
|
250
|
+
options.command = ""
|
251
|
+
options.repo = ""
|
252
|
+
options.parent = ""
|
253
|
+
|
254
|
+
myopts = OptionParser.new do |opts|
|
255
|
+
opts.banner = "Usage: #{$COMMAND_NAME} [options]"
|
256
|
+
|
257
|
+
opts.separator ""
|
258
|
+
opts.separator "Specific options:"
|
259
|
+
|
260
|
+
opts.on("-a", "--add-repo REPOSITORY", "Add a repository") do |repo|
|
261
|
+
options.command = "addrepo"
|
262
|
+
options.repo = repo
|
263
|
+
end
|
264
|
+
|
265
|
+
opts.on("-r", "--remove-repo REPOSITORY", "Remove a repository") do |repo|
|
266
|
+
options.command = "removerepo"
|
267
|
+
options.repo = repo
|
268
|
+
end
|
269
|
+
|
270
|
+
opts.on("-i", "--import-parent PARENTPATH", "Add all repositories from given parent path") do |parent|
|
271
|
+
options.command = "importparent"
|
272
|
+
options.parent = parent
|
273
|
+
end
|
274
|
+
|
275
|
+
opts.on("-l", "--list-repos", "List all managed repositories") do
|
276
|
+
options.command = "listrepos"
|
277
|
+
end
|
278
|
+
|
279
|
+
opts.on("-s", "--status", "Show status of all managed repositories") do
|
280
|
+
options.command = "status"
|
281
|
+
end
|
282
|
+
|
283
|
+
opts.on("-u", "--update-repos", "Update all managed repositories") do
|
284
|
+
options.command = "updateall"
|
285
|
+
end
|
286
|
+
|
287
|
+
opts.separator ""
|
288
|
+
opts.separator "Common options:"
|
289
|
+
|
290
|
+
opts.on_tail("-d", "--debug", "Debugging information") do
|
291
|
+
puts options
|
292
|
+
end
|
293
|
+
|
294
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
295
|
+
puts opts
|
296
|
+
exit
|
297
|
+
end
|
298
|
+
|
299
|
+
opts.on_tail("-v", "--version", "Show version") do
|
300
|
+
puts "#{$COMMAND_NAME} v.#{$VERSION}"
|
301
|
+
exit
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
myopts.parse!(args)
|
306
|
+
options
|
307
|
+
rescue
|
308
|
+
puts "Uh-oh! Missing parameter."
|
309
|
+
exit
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
##############################################################
|
314
|
+
# SCM
|
315
|
+
#
|
316
|
+
# Main class to run the Ruby Updater "rup"
|
317
|
+
#
|
318
|
+
##############################################################
|
319
|
+
class SCM
|
320
|
+
attr_reader :options
|
321
|
+
|
322
|
+
def initialize(args)
|
323
|
+
@options = OptParser.parse(args)
|
324
|
+
run_command
|
325
|
+
end
|
326
|
+
|
327
|
+
private
|
328
|
+
|
329
|
+
def run_command
|
330
|
+
case @options.command
|
331
|
+
when "addrepo"
|
332
|
+
puts LibConfig.add_repo(@options.repo)
|
333
|
+
when "removerepo"
|
334
|
+
puts LibConfig.remove_repo(@options.repo)
|
335
|
+
when "listrepos"
|
336
|
+
puts LibConfig.list_repos
|
337
|
+
when "importparent"
|
338
|
+
puts LibConfig.import_parent(@options.parent)
|
339
|
+
when "status"
|
340
|
+
LibSCM.repo_status
|
341
|
+
when "updateall"
|
342
|
+
LibSCM.update_repos
|
343
|
+
end
|
344
|
+
|
345
|
+
if @options.command.eql?("")
|
346
|
+
puts "Missing parameters! Try #{$COMMAND_NAME} -h!"
|
347
|
+
exit
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
|
353
|
+
##############################################################
|
354
|
+
#
|
355
|
+
# MAIN
|
356
|
+
#
|
357
|
+
##############################################################
|
358
|
+
SCM.new(ARGV)
|
data/lib/status.rb
ADDED
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rup
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Hans-Gunther Schmidt
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-15 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Manage multiple repositories at different locations from common SCM tool type as SVN, GIT, REPO with one simple CLI tool.
|
17
|
+
email: hans@otype.de
|
18
|
+
executables:
|
19
|
+
- rup
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
- LICENSE
|
25
|
+
- TODO
|
26
|
+
files:
|
27
|
+
- LICENSE
|
28
|
+
- README
|
29
|
+
- TODO
|
30
|
+
- Rakefile
|
31
|
+
- bin/rup
|
32
|
+
- lib/status.rb
|
33
|
+
has_rdoc: true
|
34
|
+
homepage: http://rubyforge.org/projects/rup/
|
35
|
+
licenses: []
|
36
|
+
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options: []
|
39
|
+
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
version:
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "0"
|
53
|
+
version:
|
54
|
+
requirements: []
|
55
|
+
|
56
|
+
rubyforge_project: rup
|
57
|
+
rubygems_version: 1.3.5
|
58
|
+
signing_key:
|
59
|
+
specification_version: 3
|
60
|
+
summary: SCM Repository manager in Ruby
|
61
|
+
test_files: []
|
62
|
+
|