gravitext-devtools 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +2 -0
- data/Manifest.txt +18 -0
- data/README.rdoc +31 -0
- data/Rakefile +29 -0
- data/bin/gt-cleanws +227 -0
- data/bin/gt-header +22 -0
- data/bin/gt-manifest +22 -0
- data/lib/gravitext-devtools.rb +131 -0
- data/lib/gravitext-devtools/base.rb +21 -0
- data/lib/gravitext-devtools/header_writer.rb +298 -0
- data/lib/gravitext-devtools/manifest_writer.rb +135 -0
- data/templates/format/format.java +5 -0
- data/templates/format/format.rb +5 -0
- data/templates/format/format.txt +3 -0
- data/templates/format/format.xml +5 -0
- data/templates/license/apache +13 -0
- data/templates/license/bsd +27 -0
- data/templates/license/mit +21 -0
- metadata +93 -0
data/History.rdoc
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
History.rdoc
|
2
|
+
Manifest.txt
|
3
|
+
README.rdoc
|
4
|
+
Rakefile
|
5
|
+
bin/gt-cleanws
|
6
|
+
bin/gt-header
|
7
|
+
bin/gt-manifest
|
8
|
+
lib/gravitext-devtools/base.rb
|
9
|
+
lib/gravitext-devtools.rb
|
10
|
+
lib/gravitext-devtools/header_writer.rb
|
11
|
+
lib/gravitext-devtools/manifest_writer.rb
|
12
|
+
templates/format/format.java
|
13
|
+
templates/format/format.rb
|
14
|
+
templates/format/format.txt
|
15
|
+
templates/format/format.xml
|
16
|
+
templates/license/apache
|
17
|
+
templates/license/bsd
|
18
|
+
templates/license/mit
|
data/README.rdoc
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
= gravitext-devtools
|
2
|
+
|
3
|
+
* http://github.com/dekellum/gravitext-devtools
|
4
|
+
|
5
|
+
== Description
|
6
|
+
|
7
|
+
A collection of development support tools.
|
8
|
+
|
9
|
+
gt-manifest:: Maintain manifest from git ls-files minus exclusions.
|
10
|
+
gt-cleanws:: Cleanup whitespace in files.
|
11
|
+
gt-header:: Add and maintain file license headers.
|
12
|
+
|
13
|
+
== Synopsis
|
14
|
+
|
15
|
+
[TBD]
|
16
|
+
|
17
|
+
== License
|
18
|
+
|
19
|
+
Copyright (c) 2008-2010 David Kellum
|
20
|
+
|
21
|
+
Licensed under the Apache License, Version 2.0 (the "License"); you
|
22
|
+
may not use this file except in compliance with the License. You
|
23
|
+
may obtain a copy of the License at:
|
24
|
+
|
25
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
26
|
+
|
27
|
+
Unless required by applicable law or agreed to in writing, software
|
28
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
29
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
30
|
+
implied. See the License for the specific language governing
|
31
|
+
permissions and limitations under the License.
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
$LOAD_PATH << './lib'
|
4
|
+
require 'gravitext-devtools/base'
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
gem 'rjack-tarpit', '~> 1.2.1'
|
8
|
+
require 'rjack-tarpit'
|
9
|
+
|
10
|
+
t = RJack::TarPit.new( 'gravitext-devtools', Gravitext::DevTools::VERSION )
|
11
|
+
|
12
|
+
t.specify do |h|
|
13
|
+
h.developer( 'David Kellum', 'dek-oss@gravitext.com' )
|
14
|
+
end
|
15
|
+
|
16
|
+
task :check_history_version do
|
17
|
+
t.test_line_match( 'History.rdoc', /^==/, / #{ t.version } / )
|
18
|
+
end
|
19
|
+
task :check_history_date do
|
20
|
+
t.test_line_match( 'History.rdoc', /^==/, /\([0-9\-]+\)$/ )
|
21
|
+
end
|
22
|
+
|
23
|
+
task :gem => [ :check_history_version, ]
|
24
|
+
task :tag => [ :check_history_version, :check_history_date ]
|
25
|
+
task :push => [ :check_history_version, :check_history_date ]
|
26
|
+
|
27
|
+
task :test #noop
|
28
|
+
|
29
|
+
t.define_tasks
|
data/bin/gt-cleanws
ADDED
@@ -0,0 +1,227 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
#--
|
3
|
+
# Copyright (c) 2008-2010 David Kellum
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
6
|
+
# may not use this file except in compliance with the License. You may
|
7
|
+
# 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
|
14
|
+
# implied. See the License for the specific language governing
|
15
|
+
# permissions and limitations under the License.
|
16
|
+
#++
|
17
|
+
|
18
|
+
require 'fileutils'
|
19
|
+
require 'optparse'
|
20
|
+
require 'stringio'
|
21
|
+
|
22
|
+
require 'rubygems'
|
23
|
+
require 'rainbow'
|
24
|
+
|
25
|
+
class CleanWS
|
26
|
+
include FileUtils
|
27
|
+
|
28
|
+
class NullIO
|
29
|
+
def puts(*a)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
CMAP = {}
|
34
|
+
|
35
|
+
def self.mk_tag( name, color )
|
36
|
+
tag = name.foreground( color )
|
37
|
+
CMAP[ tag ] = color
|
38
|
+
tag
|
39
|
+
end
|
40
|
+
|
41
|
+
CLEAN = mk_tag( "CLEAN", :green )
|
42
|
+
DIRTY = mk_tag( "DIRTY", :red )
|
43
|
+
WROTE = mk_tag( "WROTE", :red )
|
44
|
+
FIXED = mk_tag( "FIXED", :yellow )
|
45
|
+
NOTXT = mk_tag( "NOTXT", :blue )
|
46
|
+
|
47
|
+
def initialize
|
48
|
+
@do_write = false
|
49
|
+
@verbose = false
|
50
|
+
@show_clean = true
|
51
|
+
@fout = NullIO.new
|
52
|
+
@git_ls = false
|
53
|
+
@log = $stdout
|
54
|
+
@llines = 0
|
55
|
+
end
|
56
|
+
|
57
|
+
def parse_flags( args )
|
58
|
+
opts = OptionParser.new do |opts|
|
59
|
+
opts.banner = "Usage: cleanws [-w | -t] file ..."
|
60
|
+
opts.on( "-w", "--write", "Update file in place") do
|
61
|
+
@do_write = true
|
62
|
+
end
|
63
|
+
opts.on( "-v", "--verbose",
|
64
|
+
"Output filtered files and verbose logging.") do
|
65
|
+
@fout = $stdout
|
66
|
+
log = $stderr
|
67
|
+
@verbose = true
|
68
|
+
end
|
69
|
+
opts.on( "-d", "--dirty", "Show dirty status only.") do
|
70
|
+
@show_clean = false
|
71
|
+
end
|
72
|
+
opts.on( "-g", "--git-updates",
|
73
|
+
"Get input files from modified/untracked git working tree" ) do
|
74
|
+
@git_ls = "-m -o --exclude-standard"
|
75
|
+
end
|
76
|
+
opts.on( "-G", "--git-cached",
|
77
|
+
"Get input files from tracked/cached git files" ) do
|
78
|
+
@git_ls = "-c"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
opts.parse!( args )
|
82
|
+
end
|
83
|
+
|
84
|
+
def main( args )
|
85
|
+
|
86
|
+
parse_flags( args )
|
87
|
+
|
88
|
+
if @git_ls
|
89
|
+
gcmd = [ 'git ls-files', @git_ls, args ].flatten.join(' ')
|
90
|
+
@log.puts gcmd if @verbose
|
91
|
+
args = IO.popen( gcmd ).readlines.map { |f| f.strip }
|
92
|
+
args.reject! { |f| f =~ /\.ws(~|\.tmp)$/ }
|
93
|
+
end
|
94
|
+
|
95
|
+
args.sort!
|
96
|
+
|
97
|
+
ftypes = check_file_types( args )
|
98
|
+
|
99
|
+
any_dirty = false
|
100
|
+
|
101
|
+
ftypes.each do |ifile, type|
|
102
|
+
d = process( ifile, type )
|
103
|
+
any_dirty ||= d
|
104
|
+
end
|
105
|
+
|
106
|
+
header if @llines > 20
|
107
|
+
exit( any_dirty ? 1 : 0 )
|
108
|
+
end
|
109
|
+
|
110
|
+
def check_file_types( files )
|
111
|
+
fmap = {}
|
112
|
+
# 1: keep only regular files in fmap
|
113
|
+
files.each do |f|
|
114
|
+
if File.file?( f ) && ! File.symlink?( f )
|
115
|
+
fmap[f] = :file
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# 2: Use UNIX 'file' command to test for text files
|
120
|
+
unless fmap.empty?
|
121
|
+
IO.popen( "file " + fmap.keys.join( ' ' ) ) do |outf|
|
122
|
+
outf.each do |line|
|
123
|
+
# <filename>: <type string with /text/ or not>
|
124
|
+
if line =~ /^(.+):(.+)$/
|
125
|
+
fmap[ $1 ] = ( ( $2 =~ /text/ ) ? :text : :binary )
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
fmap.sort
|
132
|
+
end
|
133
|
+
|
134
|
+
def header
|
135
|
+
@log.puts( "%5s %4s %4s %4s %4s %s" %
|
136
|
+
[ "", "WS", "BLNK", "TABS", "LINE", "FILE" ] )
|
137
|
+
end
|
138
|
+
|
139
|
+
def process( ifile, type )
|
140
|
+
@log.puts( "CLEAN f: #{ifile} :::" ) if @verbose
|
141
|
+
|
142
|
+
ofile = nil
|
143
|
+
|
144
|
+
chg, blank, tabs, total =
|
145
|
+
if type == :text
|
146
|
+
ofile = ifile + ".ws.tmp"
|
147
|
+
|
148
|
+
fout = @do_write ? open( ofile, 'w' ) : @fout
|
149
|
+
|
150
|
+
result = open( ifile, 'r' ) do |fin|
|
151
|
+
filter( fin, fout )
|
152
|
+
end
|
153
|
+
|
154
|
+
fout.close if @do_write
|
155
|
+
result
|
156
|
+
else
|
157
|
+
[0,0,0,0]
|
158
|
+
end
|
159
|
+
|
160
|
+
change = ( ( chg + blank ) > 0 )
|
161
|
+
dirty = change || ( tabs > 0 )
|
162
|
+
|
163
|
+
state = if dirty
|
164
|
+
if @do_write
|
165
|
+
( tabs == 0 ) ? FIXED : WROTE
|
166
|
+
else
|
167
|
+
DIRTY
|
168
|
+
end
|
169
|
+
else
|
170
|
+
( type == :text ) ? CLEAN : NOTXT
|
171
|
+
end
|
172
|
+
|
173
|
+
if dirty || @show_clean
|
174
|
+
header if @llines == 0
|
175
|
+
@log.puts( "%s %4d %4d %4d %4d %s" %
|
176
|
+
[ state, chg, blank, tabs, total,
|
177
|
+
ifile.dup.foreground( CMAP[ state ] ) ] )
|
178
|
+
@llines += 1
|
179
|
+
end
|
180
|
+
|
181
|
+
if @do_write && ofile
|
182
|
+
if change
|
183
|
+
cp( ifile, ifile + ".ws~", :preserve => true )
|
184
|
+
cp( ofile, ifile )
|
185
|
+
end
|
186
|
+
rm( ofile )
|
187
|
+
end
|
188
|
+
dirty
|
189
|
+
end
|
190
|
+
|
191
|
+
# Filters files fin to fout
|
192
|
+
# All whitespace at end of line is replaced with '\n'
|
193
|
+
# Only one blank line allowed consecutively.
|
194
|
+
# Last non-empty line is terminated with '\n'
|
195
|
+
# No trailing additional lines in file.
|
196
|
+
def filter( fin, fout )
|
197
|
+
dropped_lines = 0
|
198
|
+
changed_lines = 0
|
199
|
+
tab_lines = 0
|
200
|
+
empty_lines = 0
|
201
|
+
total = 0
|
202
|
+
while( line = fin.gets )
|
203
|
+
total += 1
|
204
|
+
lstr = line.rstrip
|
205
|
+
|
206
|
+
changed_lines += 1 if ( line != ( lstr + "\n" ) )
|
207
|
+
|
208
|
+
if lstr.empty?
|
209
|
+
empty_lines += 1
|
210
|
+
else
|
211
|
+
if empty_lines > 0
|
212
|
+
fout.puts
|
213
|
+
dropped_lines += empty_lines - 1
|
214
|
+
empty_lines = 0
|
215
|
+
end
|
216
|
+
tab_lines += 1 if lstr =~ /\t/
|
217
|
+
# line.gsub!( /\t/, " " )
|
218
|
+
fout.puts lstr
|
219
|
+
end
|
220
|
+
end
|
221
|
+
dropped_lines += empty_lines
|
222
|
+
[ changed_lines, dropped_lines, tab_lines, total ]
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
226
|
+
|
227
|
+
CleanWS.new.main( ARGV )
|
data/bin/gt-header
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
#--
|
3
|
+
# Copyright (c) 2008-2010 David Kellum
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
6
|
+
# may not use this file except in compliance with the License. You may
|
7
|
+
# 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
|
14
|
+
# implied. See the License for the specific language governing
|
15
|
+
# permissions and limitations under the License.
|
16
|
+
#++
|
17
|
+
|
18
|
+
$LOAD_PATH.unshift File.join( File.dirname( __FILE__ ), "..", "lib" )
|
19
|
+
|
20
|
+
require 'gravitext-devtools/header_writer'
|
21
|
+
|
22
|
+
Gravitext::DevTools::HeaderWriter.new.run
|
data/bin/gt-manifest
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
#--
|
3
|
+
# Copyright (c) 2008-2010 David Kellum
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
6
|
+
# may not use this file except in compliance with the License. You may
|
7
|
+
# 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
|
14
|
+
# implied. See the License for the specific language governing
|
15
|
+
# permissions and limitations under the License.
|
16
|
+
#++
|
17
|
+
|
18
|
+
$LOAD_PATH.unshift File.join( File.dirname( __FILE__ ), "..", "lib" )
|
19
|
+
|
20
|
+
require 'gravitext-devtools/manifest_writer'
|
21
|
+
|
22
|
+
Gravitext::DevTools::ManifestWriter.new.run
|
@@ -0,0 +1,131 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008-2010 David Kellum
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
5
|
+
# may not use this file except in compliance with the License. You may
|
6
|
+
# obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
13
|
+
# implied. See the License for the specific language governing
|
14
|
+
# permissions and limitations under the License.
|
15
|
+
#++
|
16
|
+
|
17
|
+
require 'gravitext-devtools/base.rb'
|
18
|
+
require 'optparse'
|
19
|
+
|
20
|
+
module Gravitext
|
21
|
+
module DevTools
|
22
|
+
|
23
|
+
def self.configure
|
24
|
+
yield Gravitext::DevTools::Config
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.load_config_from_pwd
|
28
|
+
count = 0
|
29
|
+
pwd = File.expand_path( Dir.pwd )
|
30
|
+
while( File.directory?( pwd ) )
|
31
|
+
cfile = File.join( pwd, '.gt-config' )
|
32
|
+
if File.exist?( cfile )
|
33
|
+
Config::load_config( cfile )
|
34
|
+
break
|
35
|
+
end
|
36
|
+
break if File.exist?( File.join( pwd, '.git' ) )
|
37
|
+
pwd = File.dirname( pwd )
|
38
|
+
break if ( count += 1 ) > 4
|
39
|
+
break if pwd == '/'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module Config
|
44
|
+
|
45
|
+
def self.load_config( file )
|
46
|
+
puts "Loading config #{file}."
|
47
|
+
load file
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.method_missing( method, *arguments, &block )
|
51
|
+
ccall = caller[0]
|
52
|
+
puts "Method %s from %s not defined, ignored" % [ method, ccall ]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class GitFileLister
|
57
|
+
|
58
|
+
# Exclusions to the list expressed in various ways
|
59
|
+
# Array<Regexp|Proc|String>
|
60
|
+
attr_accessor :exclusions
|
61
|
+
|
62
|
+
# Flags for use in call to git ls-files
|
63
|
+
# Array<~to_s>
|
64
|
+
attr_accessor :git_flags
|
65
|
+
|
66
|
+
# Additional files to add to files list
|
67
|
+
# Array<~to_s>
|
68
|
+
attr_accessor :extra_files
|
69
|
+
|
70
|
+
def initialize
|
71
|
+
@args = []
|
72
|
+
@files = nil
|
73
|
+
@exclusions = [ %r{(^|/).gitignore$}, # gt-manifest, gt-header
|
74
|
+
%r{(^|/).gt-config$}, # gt-manifest, (gt-header)
|
75
|
+
%r{(^|/)src(/|$)}, # gt-manifest
|
76
|
+
'lib/**/*.jar', # all
|
77
|
+
'Manifest.static' ] # gt-manifest, gt-header
|
78
|
+
@git_flags = []
|
79
|
+
@extra_files = []
|
80
|
+
end
|
81
|
+
|
82
|
+
def parse_options( args = ARGV, &block )
|
83
|
+
opts = OptionParser.new do |opts|
|
84
|
+
opts.on( "-g", "--git-updates",
|
85
|
+
"Include files from modified/untracked git working tree" ) do
|
86
|
+
@git_flags += %w[ -m -o --exclude-standard ]
|
87
|
+
end
|
88
|
+
block.call( opts ) if block
|
89
|
+
end
|
90
|
+
@args = opts.parse( args )
|
91
|
+
end
|
92
|
+
|
93
|
+
def files
|
94
|
+
@files ||= generate_list
|
95
|
+
end
|
96
|
+
|
97
|
+
def generate_list( args = @args )
|
98
|
+
|
99
|
+
files, dirs = args.partition { |a| File.file?( a ) }
|
100
|
+
|
101
|
+
if files.empty? || ! dirs.empty?
|
102
|
+
gcmd = [ 'git', 'ls-files', @git_flags, dirs ].flatten.compact.join( ' ' )
|
103
|
+
files += IO.popen( gcmd ) { |inp| inp.readlines }
|
104
|
+
end
|
105
|
+
|
106
|
+
files += extra_files
|
107
|
+
|
108
|
+
files.map! { |f| f.strip }
|
109
|
+
files.uniq!
|
110
|
+
files.reject { |f| exclude?( f ) }
|
111
|
+
end
|
112
|
+
|
113
|
+
def exclude?( fname )
|
114
|
+
@exclusions.any? do |ex|
|
115
|
+
case ex
|
116
|
+
when Proc
|
117
|
+
ex.call( fname )
|
118
|
+
when Regexp
|
119
|
+
fname =~ ex
|
120
|
+
when /[*?]/
|
121
|
+
File.fnmatch?( ex, fname, File::FNM_PATHNAME )
|
122
|
+
else
|
123
|
+
fname == ex
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008-2010 David Kellum
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
5
|
+
# may not use this file except in compliance with the License. You may
|
6
|
+
# obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
13
|
+
# implied. See the License for the specific language governing
|
14
|
+
# permissions and limitations under the License.
|
15
|
+
#++
|
16
|
+
|
17
|
+
module Gravitext
|
18
|
+
module DevTools
|
19
|
+
VERSION = "1.0.0"
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,298 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008-2010 David Kellum
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
5
|
+
# may not use this file except in compliance with the License. You may
|
6
|
+
# obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
13
|
+
# implied. See the License for the specific language governing
|
14
|
+
# permissions and limitations under the License.
|
15
|
+
#++
|
16
|
+
|
17
|
+
require 'gravitext-devtools'
|
18
|
+
require 'fileutils'
|
19
|
+
require 'erb'
|
20
|
+
require 'rubygems'
|
21
|
+
require 'rainbow'
|
22
|
+
|
23
|
+
module Gravitext
|
24
|
+
module DevTools
|
25
|
+
|
26
|
+
module Config
|
27
|
+
def self.header
|
28
|
+
hw = HeaderWriter.instance
|
29
|
+
raise "HeaderWriter not initialized" unless hw
|
30
|
+
yield hw
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class HeaderWriter
|
35
|
+
include FileUtils
|
36
|
+
|
37
|
+
attr_accessor :verbose
|
38
|
+
attr_accessor :holder
|
39
|
+
attr_accessor :inception
|
40
|
+
attr_accessor :license
|
41
|
+
attr_accessor :exclusions
|
42
|
+
|
43
|
+
class << self
|
44
|
+
attr_accessor :instance
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize
|
48
|
+
@verbose = false
|
49
|
+
@do_write = false
|
50
|
+
@license = :apache
|
51
|
+
@inception = Time.now.year
|
52
|
+
|
53
|
+
@git_lister = GitFileLister.new
|
54
|
+
|
55
|
+
@exclusions = [ '**/.gitignore',
|
56
|
+
'**/.gt-config',
|
57
|
+
'**/History.rdoc',
|
58
|
+
'**/History.txt',
|
59
|
+
'**/Manifest.static',
|
60
|
+
'**/Manifest.txt',
|
61
|
+
'**/*.jar',
|
62
|
+
'**/Rakefile',
|
63
|
+
'**/pom.xml',
|
64
|
+
'**/assembly.xml']
|
65
|
+
|
66
|
+
@cached_header = {}
|
67
|
+
|
68
|
+
HeaderWriter.instance = self # The last created
|
69
|
+
end
|
70
|
+
|
71
|
+
def parse_options( args = ARGV )
|
72
|
+
|
73
|
+
@git_lister.parse_options( args ) do |opts|
|
74
|
+
opts.banner = "Usage: gt-manifest [dir|file] ..."
|
75
|
+
opts.on( "-v", "--verbose",
|
76
|
+
"Output full manifest details" ) do
|
77
|
+
@verbose = true
|
78
|
+
end
|
79
|
+
opts.on( "-w", "--write",
|
80
|
+
"Write headers if needed" ) do
|
81
|
+
@do_write = true
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def run( args = ARGV )
|
88
|
+
|
89
|
+
parse_options( args )
|
90
|
+
|
91
|
+
Gravitext::DevTools.load_config_from_pwd
|
92
|
+
|
93
|
+
@git_lister.exclusions = @exclusions
|
94
|
+
# puts @exclusions.inspect
|
95
|
+
|
96
|
+
files = @git_lister.files
|
97
|
+
|
98
|
+
# puts cached_header( :rb )
|
99
|
+
# exit
|
100
|
+
|
101
|
+
files.each do |fname|
|
102
|
+
HeaderProcessor.new( fname, @do_write ).process
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
TDIR = File.expand_path( File.join( File.dirname( __FILE__ ),
|
107
|
+
'..', '..', 'templates' ) )
|
108
|
+
|
109
|
+
def cached_header( format )
|
110
|
+
@cached_header[ format ] ||= gen_header( format )
|
111
|
+
end
|
112
|
+
|
113
|
+
def gen_header( format )
|
114
|
+
efile = File.join( TDIR, 'format', "format.#{format}" )
|
115
|
+
license = cached_license
|
116
|
+
expand( IO.read( efile ), binding )
|
117
|
+
end
|
118
|
+
|
119
|
+
def cached_license
|
120
|
+
@cached_license ||= gen_license
|
121
|
+
end
|
122
|
+
|
123
|
+
def gen_license
|
124
|
+
template = if license.is_a?( Symbol )
|
125
|
+
IO.read( File.join( TDIR, 'license', license.to_s ) )
|
126
|
+
else
|
127
|
+
license.to_s
|
128
|
+
end
|
129
|
+
expand( template, binding )
|
130
|
+
end
|
131
|
+
|
132
|
+
def expand( template, bnd )
|
133
|
+
ERB.new( template, nil, '%' ).result( bnd ).map { |l| l.rstrip }
|
134
|
+
end
|
135
|
+
|
136
|
+
def years
|
137
|
+
@years ||= [ inception, Time.now.year ].uniq.join( '-' )
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class HeaderProcessor
|
142
|
+
|
143
|
+
CMAP = {}
|
144
|
+
|
145
|
+
def self.mk_tag( name, color )
|
146
|
+
tag = name.foreground( color )
|
147
|
+
CMAP[ tag ] = color
|
148
|
+
tag
|
149
|
+
end
|
150
|
+
|
151
|
+
GOOD = mk_tag( "GOOD ", :green )
|
152
|
+
NONE = mk_tag( "NONE ", :red )
|
153
|
+
DATE = mk_tag( "DATE ", :cyan )
|
154
|
+
EMPTY = mk_tag( "EMPTY", :yellow )
|
155
|
+
WROTE = mk_tag( "WROTE", :yellow )
|
156
|
+
|
157
|
+
def initialize( fname, do_write = false )
|
158
|
+
@cpos = 0
|
159
|
+
@do_write = do_write
|
160
|
+
@fname = fname
|
161
|
+
@format = case fname
|
162
|
+
when /\.java$/
|
163
|
+
:java
|
164
|
+
when /\.xml$/
|
165
|
+
:xml
|
166
|
+
when /\.rb$/
|
167
|
+
:rb
|
168
|
+
else
|
169
|
+
:txt
|
170
|
+
end
|
171
|
+
@state = :first
|
172
|
+
@writer = HeaderWriter.instance
|
173
|
+
end
|
174
|
+
|
175
|
+
def process
|
176
|
+
state = GOOD
|
177
|
+
@lines = IO.readlines( @fname )
|
178
|
+
if @lines.empty?
|
179
|
+
state = EMPTY
|
180
|
+
else
|
181
|
+
scan_prolog
|
182
|
+
if find_copyright
|
183
|
+
if !check_copyright
|
184
|
+
if @do_write
|
185
|
+
rewrite_file
|
186
|
+
state = WROTE
|
187
|
+
else
|
188
|
+
state = DATE
|
189
|
+
end
|
190
|
+
end
|
191
|
+
else
|
192
|
+
if @do_write
|
193
|
+
insert_header
|
194
|
+
rewrite_file
|
195
|
+
state = WROTE
|
196
|
+
else
|
197
|
+
state = NONE
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
puts( "%s %s" %
|
202
|
+
[ state, @fname.dup.foreground( CMAP[ state ] ) ] )
|
203
|
+
end
|
204
|
+
|
205
|
+
def rewrite_file
|
206
|
+
open( @fname, "w" ) { |fout| fout.puts( @lines ) }
|
207
|
+
end
|
208
|
+
|
209
|
+
def scan_prolog
|
210
|
+
|
211
|
+
if @lines[0] =~ /^#\!([^\s]+)/
|
212
|
+
@format = :rb if $1 =~ /ruby$/
|
213
|
+
@cpos = 1
|
214
|
+
end
|
215
|
+
|
216
|
+
if @lines[0] =~ /^<\?xml/
|
217
|
+
@format = :xml
|
218
|
+
@cpos = 1
|
219
|
+
end
|
220
|
+
|
221
|
+
@lines.each_index do |i|
|
222
|
+
line = @lines[i]
|
223
|
+
if line =~ /^#.*-\*-\s*ruby\s*-\*-/
|
224
|
+
@format = :rb
|
225
|
+
@cpos = i+1
|
226
|
+
break
|
227
|
+
else
|
228
|
+
break if line !~ /^\s*#/
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
233
|
+
|
234
|
+
def find_copyright
|
235
|
+
@cline = nil
|
236
|
+
@lines.each_index do |i|
|
237
|
+
line = @lines[i]
|
238
|
+
case @format
|
239
|
+
when :rb
|
240
|
+
case line
|
241
|
+
when /^#\s+Copyright/
|
242
|
+
@cline = i
|
243
|
+
break
|
244
|
+
when /^\s*$/
|
245
|
+
when /^\s*[^#]/
|
246
|
+
break
|
247
|
+
end
|
248
|
+
when :java
|
249
|
+
case line
|
250
|
+
when /^\s*\*\s+Copyright/
|
251
|
+
@cline = i
|
252
|
+
break
|
253
|
+
when /^\s*$/
|
254
|
+
when /^\s*[^\/\*]/
|
255
|
+
break
|
256
|
+
end
|
257
|
+
else
|
258
|
+
if line =~ /Copyright \([cC]\)/
|
259
|
+
@cline = i
|
260
|
+
break
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
@cline
|
265
|
+
end
|
266
|
+
|
267
|
+
def check_copyright
|
268
|
+
passes =
|
269
|
+
if @lines[@cline] =~ /Copyright \(c\) (\d{4})(-(\d{4}))? (\S.*)\s*$/
|
270
|
+
ldate = $3 || $1 #last date
|
271
|
+
ldate && ( ldate == Time.now.year.to_s ) && ( $4 == @writer.holder )
|
272
|
+
else
|
273
|
+
false
|
274
|
+
end
|
275
|
+
|
276
|
+
unless passes
|
277
|
+
start = @lines[@cline].match( /^.*Copyright/ )
|
278
|
+
@lines[@cline] = [ start, "(c)",
|
279
|
+
@writer.years, @writer.holder ].join( ' ' )
|
280
|
+
end
|
281
|
+
|
282
|
+
passes
|
283
|
+
end
|
284
|
+
|
285
|
+
def insert_header
|
286
|
+
header = @writer.cached_header( @format )
|
287
|
+
@lines.insert( @cpos, *header )
|
288
|
+
@cpos += header.length
|
289
|
+
# Insert an extra line break if needed.
|
290
|
+
unless @lines[ @cpos ] =~ /^\s*$/ || @format == :xml
|
291
|
+
@lines.insert( @cpos, "" )
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
end
|
296
|
+
|
297
|
+
end
|
298
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008-2010 David Kellum
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
5
|
+
# may not use this file except in compliance with the License. You may
|
6
|
+
# obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
13
|
+
# implied. See the License for the specific language governing
|
14
|
+
# permissions and limitations under the License.
|
15
|
+
#++
|
16
|
+
|
17
|
+
require 'gravitext-devtools'
|
18
|
+
require 'fileutils'
|
19
|
+
|
20
|
+
module Gravitext
|
21
|
+
module DevTools
|
22
|
+
|
23
|
+
class ManifestWriter
|
24
|
+
include FileUtils
|
25
|
+
include Gravitext::DevTools
|
26
|
+
|
27
|
+
# Set true if Manifest.txt should be written instead of Manifest.txt.
|
28
|
+
# (Default: true if Manifest.static exists)
|
29
|
+
# Boolean
|
30
|
+
attr_accessor :static
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
@verbose = false
|
34
|
+
@static = File.exist?( 'Manifest.static' )
|
35
|
+
|
36
|
+
@git_lister = GitFileLister.new
|
37
|
+
|
38
|
+
@git_lister.exclusions = [ %r{(^|/).gitignore$},
|
39
|
+
%r{(^|/).gt-config$},
|
40
|
+
%r{(^|/)src(/|$)},
|
41
|
+
'lib/**/*.jar',
|
42
|
+
'Manifest.static' ]
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse_options( args = ARGV )
|
46
|
+
|
47
|
+
@git_lister.parse_options( args ) do |opts|
|
48
|
+
opts.banner = "Usage: gt-manifest [dir|file] ..."
|
49
|
+
opts.on( "-v", "--verbose",
|
50
|
+
"Output full manifest details" ) do
|
51
|
+
@verbose = true
|
52
|
+
end
|
53
|
+
opts.on( "-s", "--static",
|
54
|
+
"Write to Manifest.static instead of Manifest.txt" ) do
|
55
|
+
@static = true
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def run( args = ARGV )
|
61
|
+
|
62
|
+
parse_options( args )
|
63
|
+
|
64
|
+
@git_lister.extra_files << 'Manifest.txt' unless @static
|
65
|
+
@git_lister.git_flags << '-c' # Include cached by default
|
66
|
+
|
67
|
+
files = @git_lister.files
|
68
|
+
|
69
|
+
files.map! do |f|
|
70
|
+
f = f.split( File::SEPARATOR )
|
71
|
+
f.shift if f[0] == '.'
|
72
|
+
f
|
73
|
+
end
|
74
|
+
files.uniq!
|
75
|
+
files = sort( files )
|
76
|
+
files.map! { |f| File.join( f ) }
|
77
|
+
|
78
|
+
open( 'Manifest.' + ( @static ? 'static' : 'txt' ), 'w' ) do |out|
|
79
|
+
files.each do |fname|
|
80
|
+
puts fname if @verbose
|
81
|
+
out.puts fname
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def sort( files )
|
87
|
+
|
88
|
+
files = files.sort do |a,b|
|
89
|
+
i = 0
|
90
|
+
o = 0
|
91
|
+
while( o == 0 )
|
92
|
+
o = -1 if ( a.length == i+1 ) && a.length < b.length
|
93
|
+
o = 1 if ( b.length == i+1 ) && a.length > b.length
|
94
|
+
o = a[i] <=> b[i] if o == 0
|
95
|
+
i += 1
|
96
|
+
end
|
97
|
+
o
|
98
|
+
end
|
99
|
+
|
100
|
+
files = priority_to_base( files )
|
101
|
+
|
102
|
+
files
|
103
|
+
end
|
104
|
+
|
105
|
+
# Move up any foo/base.rb or version.rb files. By convention
|
106
|
+
# (originally based on rdoc issues) these come before a foo.rb, i.e:
|
107
|
+
#
|
108
|
+
# lib/foo/base.rb
|
109
|
+
# lib/foo.rb
|
110
|
+
# lib/foo/other.rb
|
111
|
+
#
|
112
|
+
def priority_to_base( files )
|
113
|
+
|
114
|
+
bases, nfiles = files.partition { |f| f.last =~ /^(base|version)\.rb$/ }
|
115
|
+
|
116
|
+
bases.each do |base|
|
117
|
+
key = base[0..-2]
|
118
|
+
key[-1] += ".rb"
|
119
|
+
nfiles.each_with_index do |file, i|
|
120
|
+
if file == key
|
121
|
+
nfiles.insert( i, base )
|
122
|
+
base = nil
|
123
|
+
break
|
124
|
+
end
|
125
|
+
end
|
126
|
+
return files if base
|
127
|
+
end
|
128
|
+
|
129
|
+
nfiles
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright (c) <%= years %> <%= holder %>
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License"); you
|
4
|
+
may not use this file except in compliance with the License. You may
|
5
|
+
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
|
12
|
+
implied. See the License for the specific language governing
|
13
|
+
permissions and limitations under the License.
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Copyright (c) <%= years %> <%= holder %>
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are
|
6
|
+
met:
|
7
|
+
|
8
|
+
* Redistributions of source code must retain the above copyright
|
9
|
+
notice, this list of conditions and the following disclaimer.
|
10
|
+
* Redistributions in binary form must reproduce the above copyright
|
11
|
+
notice, this list of conditions and the following disclaimer in the
|
12
|
+
documentation and/or other materials provided with the distribution.
|
13
|
+
* Neither the name of RJack nor the names of its contributors may be
|
14
|
+
used to endorse or promote products derived from this software
|
15
|
+
without specific prior written permission.
|
16
|
+
|
17
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
18
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
19
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
20
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
21
|
+
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
22
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
23
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
24
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
25
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
26
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
27
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) <%= years %> <%= holder %>
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gravitext-devtools
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David Kellum
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-04-21 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rjack-tarpit
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.2.1
|
24
|
+
version:
|
25
|
+
description: |-
|
26
|
+
A collection of development support tools.
|
27
|
+
|
28
|
+
gt-manifest:: Maintain manifest from git ls-files minus exclusions.
|
29
|
+
gt-cleanws:: Cleanup whitespace in files.
|
30
|
+
gt-header:: Add and maintain file license headers.
|
31
|
+
email:
|
32
|
+
- dek-oss@gravitext.com
|
33
|
+
executables:
|
34
|
+
- gt-cleanws
|
35
|
+
- gt-header
|
36
|
+
- gt-manifest
|
37
|
+
extensions: []
|
38
|
+
|
39
|
+
extra_rdoc_files:
|
40
|
+
- Manifest.txt
|
41
|
+
- templates/format/format.txt
|
42
|
+
- README.rdoc
|
43
|
+
- History.rdoc
|
44
|
+
files:
|
45
|
+
- History.rdoc
|
46
|
+
- Manifest.txt
|
47
|
+
- README.rdoc
|
48
|
+
- Rakefile
|
49
|
+
- bin/gt-cleanws
|
50
|
+
- bin/gt-header
|
51
|
+
- bin/gt-manifest
|
52
|
+
- lib/gravitext-devtools/base.rb
|
53
|
+
- lib/gravitext-devtools.rb
|
54
|
+
- lib/gravitext-devtools/header_writer.rb
|
55
|
+
- lib/gravitext-devtools/manifest_writer.rb
|
56
|
+
- templates/format/format.java
|
57
|
+
- templates/format/format.rb
|
58
|
+
- templates/format/format.txt
|
59
|
+
- templates/format/format.xml
|
60
|
+
- templates/license/apache
|
61
|
+
- templates/license/bsd
|
62
|
+
- templates/license/mit
|
63
|
+
has_rdoc: true
|
64
|
+
homepage: http://github.com/dekellum/gravitext-devtools
|
65
|
+
licenses: []
|
66
|
+
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options:
|
69
|
+
- --main
|
70
|
+
- README.rdoc
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
version:
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: "0"
|
84
|
+
version:
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
rubyforge_project: gravitext-devtools
|
88
|
+
rubygems_version: 1.3.5
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: A collection of development support tools
|
92
|
+
test_files: []
|
93
|
+
|