code-tools 5.0.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5bccd6fecbea6c93c32b92522d03fc000ebe403b
4
+ data.tar.gz: 927adb322732ca9f2f37cff0372d0f5c215810be
5
+ SHA512:
6
+ metadata.gz: 596b5fec512b56871f04ed48d2633fd567ba80efa53c7b2bb5732b92643d707e8b8dcf76651dcea097b3323a8b212f0f6957ace5fef32ea9a543c780b8b83bd1
7
+ data.tar.gz: e9335f94a397cc1333d31aa0bd3df41fb3aa282840f1e50c39f07bfd67091d600d25572c0db1e9e59a7a8f72b312b0d5c14c4b5fd44a904aba874aa1e053a80b
data/bin/code-tools ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ puts "vamper - Version stamper"
3
+ puts "ender - CR/LF line ending fixer"
4
+ puts "spacer - Space/tab line fixer"
data/bin/ender ADDED
@@ -0,0 +1,153 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ require 'methadone'
6
+
7
+ class Tool
8
+ include Methadone::Main
9
+ include Methadone::CLILogging
10
+
11
+ main do |input_file|
12
+ unless File.exist?(input_file)
13
+ error "File #{input_file} does not exist"
14
+ next 1
15
+ end
16
+
17
+ output_file = options[:output_file]
18
+
19
+ if output_file.nil?
20
+ output_file = input_file
21
+ end
22
+
23
+ # Read the entire file and determine all the different line endings
24
+ file_contents = IO.read(input_file)
25
+ num_cr = 0
26
+ num_lf = 0
27
+ num_crlf = 0
28
+ num_lines = 1
29
+
30
+ i = 0
31
+ while i < file_contents.length do
32
+ c = file_contents[i]
33
+
34
+ if c == "\r"
35
+ if i < file_contents.length - 1 and file_contents[i + 1] == "\n"
36
+ num_crlf += 1
37
+ i += 1
38
+ else
39
+ num_cr += 1
40
+ end
41
+
42
+ num_lines += 1
43
+ elsif c == "\n"
44
+ num_lf += 1
45
+ num_lines += 1
46
+ end
47
+ i += 1
48
+ end
49
+
50
+ num_endings = (num_cr > 0 ? 1 : 0) + (num_lf > 0 ? 1 : 0) + (num_crlf > 0 ? 1 : 0)
51
+ le = num_endings > 1 ? :mixed : num_cr > 0 ? :cr : num_lf > 0 ? :lf : :crlf
52
+ msg = "\"#{input_file}\", #{le.to_s}, #{num_lines} lines"
53
+
54
+ if options[:mode].nil?
55
+ info msg
56
+ next 1
57
+ end
58
+
59
+ if options[:mode] == :auto
60
+ # Find the most common line ending and make that the automatic line ending
61
+ auto_line_ending = :lf
62
+ n = num_lf
63
+
64
+ if num_crlf > n
65
+ auto_line_ending = :crlf
66
+ n = num_crlf
67
+ end
68
+
69
+ if num_cr > n
70
+ auto_line_ending = :cr
71
+ end
72
+
73
+ options[:mode] = auto_line_ending
74
+ end
75
+
76
+ new_num_lines = 1
77
+
78
+ if (options[:mode] == :cr and num_cr + 1 == num_lines) or
79
+ (options[:mode] == :lf and num_lf + 1 == num_lines) or
80
+ (options[:mode] == :crlf and num_crlf + 1 == num_lines)
81
+ # We're not changing the line endings; nothing to do
82
+ new_num_lines = num_lines
83
+ else
84
+ newline_chars =
85
+ options[:mode] == :cr ? "\r" :
86
+ options[:mode] == :lf ? "\n" :
87
+ "\r\n"
88
+
89
+ file = nil
90
+
91
+ begin
92
+ file = File.new(output_file, 'w')
93
+
94
+ i = 0
95
+ while i < file_contents.length
96
+ c = file_contents[i]
97
+
98
+ if c == "\r"
99
+ if i < file_contents.length - 1 && file_contents[i + 1] == "\n"
100
+ i += 1
101
+ end
102
+
103
+ new_num_lines += 1
104
+ file.write(newline_chars)
105
+ elsif c == "\n"
106
+ new_num_lines += 1
107
+ file.write(newline_chars)
108
+ else
109
+ file.write(c)
110
+ end
111
+
112
+ i += 1
113
+ end
114
+ rescue Exception => e
115
+ error "unable to write #{output_file}. #{e.to_s}"
116
+ next 1
117
+ ensure
118
+ file.close() unless !file
119
+ end
120
+
121
+ msg += " -> \"#{output_file}\", #{options[:mode].to_s}, #{new_num_lines} lines"
122
+ end
123
+
124
+ info msg
125
+ end
126
+
127
+ change_logger Methadone::CLILogger.new
128
+
129
+ description 'Ender - the line ending fixer'
130
+ version '5.0.0'
131
+
132
+ on("-o", "--output-file FILE", "The output file. Default is the same as the input file.")
133
+ on("-m", "--mode MODE",
134
+ "The convert mode, either auto, cr, lf, crlf. auto will use the most commonly occurring ending. "\
135
+ "Updates will only be done when this argument is given.") do |mode|
136
+ options[:mode] = case mode
137
+ when 'auto', 'a'
138
+ :auto
139
+ when 'lf'
140
+ :lf
141
+ when 'cr'
142
+ :cr
143
+ when 'crlf'
144
+ :crlf
145
+ else
146
+ exit_now! "Unknown mode #{mode}"
147
+ end
148
+ end
149
+
150
+ arg :input_file, "Input file to check or convert"
151
+
152
+ go!
153
+ end
data/bin/spacer ADDED
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ require 'methadone'
6
+ require 'spacer'
7
+
8
+ class Tool
9
+ include Methadone::Main
10
+ include Methadone::CLILogging
11
+
12
+ # When reporting the tool indicates beginning-of-line \(BOL\) tabs and spaces.
13
+ # When replacing, all tabs not at the beginning of a line are replaced with spaces.
14
+ # Spaces and tabs inside multi-line C# strings (@"...") and inside Ruby \%Q\(...\) strings
15
+ # are ignored.
16
+ # Note that conversion to tabs may still leave the file as mixed as some lines may have
17
+ # spaces that are not a whole number multiple of the tabstop size. In that case use the
18
+ # -round option to remove smooth out the spurious spaces.
19
+
20
+ def self.get_whitespace_type(bol)
21
+ (bol.tabs > 0) ? (bol.spaces > 0 ? :mixed : :tabs) : :spaces
22
+ end
23
+
24
+ def self.read_file_lines(filename)
25
+ # Read the entire file
26
+ file_contents = File.read(filename)
27
+
28
+ # Convert to a list of lines, preserving the end-of-lines
29
+ lines = []
30
+ s = 0
31
+ i = 0
32
+
33
+ while i < file_contents.length do
34
+ c = file_contents[i]
35
+ c1 = i < file_contents.length - 1 ? file_contents[i + 1] : "\0"
36
+
37
+ if c == "\r"
38
+ i += 1
39
+
40
+ if c1 == "\n"
41
+ i += 1
42
+ end
43
+ elsif c == "\n"
44
+ i += 1
45
+ else
46
+ i += 1
47
+ next
48
+ end
49
+
50
+ lines.push(file_contents[s, i - s])
51
+ s = i
52
+ end
53
+
54
+ if s != i
55
+ lines.push(file_contents[s, i - s])
56
+ end
57
+
58
+ lines
59
+ end
60
+
61
+ main do |input_file|
62
+ unless File.exist?(input_file)
63
+ error "File #{input_file} does not exist"
64
+ next 1
65
+ end
66
+
67
+ output_file = options[:output_file]
68
+
69
+ if output_file.nil?
70
+ output_file = input_file
71
+ end
72
+
73
+ if File.extname(input_file) == '.cs'
74
+ file_type = :csharp
75
+ else
76
+ file_type = :text
77
+ end
78
+
79
+ lines = read_file_lines(input_file)
80
+
81
+ if file_type == :text
82
+ before = Spacer::Text.count_bol_spaces_and_tabs(lines)
83
+ else
84
+ before = Spacer::CSharp.count_bol_spaces_and_tabs(lines)
85
+ end
86
+
87
+ if !options[:mode].nil?
88
+ if file_type == :text
89
+ Spacer::Text.untabify(lines, options[:tabsize])
90
+ else
91
+ Spacer::CSharp.untabify(lines, options[:tabsize])
92
+ end
93
+
94
+ if options[:mode] == :tabs
95
+ if file_type == :text
96
+ Spacer::Text.tabify(lines, options[:tabsize], options[:round])
97
+ else
98
+ Spacer::CSharp.tabify(lines, options[:tabsize], options[:round])
99
+ end
100
+ end
101
+ end
102
+
103
+ msg = "\"#{input_file}\", #{file_type.to_s}, #{get_whitespace_type(before).to_s}"
104
+
105
+ if !options[:mode].nil?
106
+ if file_type == :text
107
+ after = Spacer::Text.count_bol_spaces_and_tabs(lines)
108
+ else
109
+ after = Spacer::CSharp.count_bol_spaces_and_tabs(lines)
110
+ end
111
+
112
+ file = nil
113
+
114
+ begin
115
+ file = File.new(output_file, 'w')
116
+
117
+ for line in lines do
118
+ file.write(line)
119
+ end
120
+ ensure
121
+ file.close() unless file == nil
122
+ end
123
+
124
+ msg += " -> \"#{output_file}\", #{get_whitespace_type(after).to_s}"
125
+ end
126
+
127
+ info msg
128
+ end
129
+
130
+ description 'Spacer - source file space/tab fixer tool'
131
+ version '5.0.0'
132
+
133
+ options[:tabsize] = 4
134
+ options[:round] = false
135
+
136
+ on("-o", "--output-file FILE", "The output file. Default is the same as the input file.")
137
+ on("-m", "--mode MODE","The convert mode (tabs or spaces) Default is to just display the files current state."\
138
+ "Updates will only be done when this argument is given.") do |mode|
139
+ options[:mode] = case mode
140
+ when 'tabs', 't'
141
+ :tabs
142
+ when 'spaces', 's'
143
+ :spaces
144
+ else
145
+ exit_now! "Unknown mode #{mode}"
146
+ end
147
+ end
148
+ on("-t", "--tabsize TABSIZE", "Tab size in spaces to assume. Default is #{options[:tabsize]} spaces.")
149
+ on("-r", "--round", "When tabifying, round BOL spaces down to an exact number of tabs.")
150
+
151
+ arg :input_file, "Input file to check or convert"
152
+
153
+ go!
154
+ end
data/bin/vamper ADDED
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ require 'methadone'
6
+ require 'vamper'
7
+ require 'tzinfo'
8
+
9
+ class Tool
10
+ include Methadone::Main
11
+ include Methadone::CLILogging
12
+
13
+ def self.find_version_file()
14
+ dir = Dir.pwd
15
+
16
+ while dir.length != 0
17
+ files = Dir.glob('*.version')
18
+ if files.length > 0
19
+ file = files[0]
20
+ break
21
+ else
22
+ if dir == '/'
23
+ dir = ''
24
+ else
25
+ dir = File.expand_path('..', dir)
26
+ end
27
+ end
28
+ end
29
+
30
+ if file.nil?
31
+ exit_now! 'Unable to find a .version file in this or parent directories.'
32
+ end
33
+
34
+ file
35
+ end
36
+
37
+ def self.get_full_date(now)
38
+ now.year * 10000 + now.month * 100 + now.mday
39
+ end
40
+
41
+ def get_jdate(now, start_year)
42
+ (((now.year - start_year + 1) * 10000) + (now.month * 100) + now.mday).to_s
43
+ end
44
+
45
+ main do |input_file|
46
+ if input_file.nil? or !File.exist?(input_file)
47
+ input_file = find_version_file
48
+ end
49
+
50
+ input_file = File.expand_path(input_file)
51
+
52
+ project_name = File.basename(input_file, '.version')
53
+ version_config_file_name = "#{File.dirname(input_file)}/#{project_name}.version.config"
54
+
55
+ info "Version file is '#{input_file}'"
56
+ info "Version config is '#{version_config_file_name}'"
57
+ info "Project name is '#{project_name}'"
58
+
59
+ if File.exists?(input_file)
60
+ version_data = Vamper::VersionFile.new(File.open(input_file))
61
+ else
62
+ version_data = Vamper::VersionFile.new
63
+ end
64
+
65
+ now = TZInfo::Timezone.get(version_data.time_zone).now
66
+
67
+ case version_data.build_value_type
68
+ when :JDate
69
+ build = get_jdate(now, version_data.start_year)
70
+
71
+ if version_data.build != build
72
+ version_data.revision = 0
73
+ version_data.build = build
74
+ else
75
+ version_data.revision += 1
76
+ end
77
+ when :Incremental
78
+ version_data.build += 1
79
+ version_data.revision = 0
80
+ else # :FullDate
81
+ build = get_full_date(now)
82
+
83
+ if version_data.build != build
84
+ version_data.revision = 0
85
+ version_data.build = build
86
+ else
87
+ version_data.revision += 1
88
+ end
89
+ end
90
+
91
+ tags = version_data.tags
92
+
93
+ case version_data.build_value_type
94
+ when :FullDate
95
+ build_str = build.to_s
96
+ tags[:DashBuild] = build_str[0..3] + '-' + build_str[4..5] + '-' + build_str[6..7]
97
+ end
98
+
99
+ info 'Version tags are:'
100
+ tags.each { |key, value|
101
+ info " #{key}=#{value}"
102
+ }
103
+
104
+ if options[:update]
105
+ info 'Updating version information:'
106
+ end
107
+
108
+ unless File.exists?(version_config_file_name)
109
+ FileUtils.cp(Vamper::VersionConfigFile.get_default_file, version_config_file_name)
110
+ end
111
+
112
+ version_config_file = Vamper::VersionConfigFile.new(File.open(version_config_file_name), tags)
113
+ file_list = version_data.files.map { |file_name| file_name.replace_tags!(tags) }
114
+
115
+ file_list.each do |file_name|
116
+ path = File.expand_path(File.join(File.dirname(input_file), file_name))
117
+ path_file_name = File.basename(path)
118
+ match = false
119
+
120
+ for file_type in version_config_file.file_types do
121
+ match = file_type.file_specs.any? { |file_spec| file_spec.match(path_file_name) }
122
+ unless match
123
+ next
124
+ end
125
+
126
+ if file_type.write
127
+ dir = File.dirname(path)
128
+ unless Dir.exists?(dir)
129
+ error "Directory '#{dir}' does not exist to write file ''#{path_file_name}''"
130
+ exit(1)
131
+ end
132
+
133
+ if options[:update]
134
+ IO.write(path, file_type.write)
135
+ end
136
+ else # !file_type.write
137
+ if File.exists?(path)
138
+ if options[:update]
139
+ file_type.updates.each do |update|
140
+ content = IO.read(path)
141
+ # At this point the only ${...} variables left in the replace strings are Before and After
142
+ # This line converts the ${...} into \k<...> to put captured groups from search back
143
+ # into the replace string.
144
+ content.gsub!(%r(#{update.search})m, update.replace.gsub(/\${(\w+)}/,'\\\\k<\\1>'))
145
+ IO.write(path, content)
146
+ end
147
+ end
148
+ else
149
+ error "file #{path} does not exist to update"
150
+ exit(1)
151
+ end
152
+ end
153
+
154
+ break
155
+ end
156
+
157
+ unless match
158
+ error "file '#{path}' has no matching file type in the .version.config"
159
+ exit(1)
160
+ end
161
+
162
+ info path
163
+
164
+ if options[:update]
165
+ version_data.write_to(File.open(input_file, 'w'))
166
+ end
167
+ end
168
+ end
169
+
170
+ description 'Vamper - file version stamper'
171
+ version '5.0.0'
172
+
173
+ options[:update] = false
174
+
175
+ on("-u", "--update", "Actually do the update.")
176
+
177
+ arg :input_file, "A version file. Default is to search parent directories for *.version", :optional
178
+
179
+ go!
180
+ end
data/lib/core_ext.rb ADDED
@@ -0,0 +1,54 @@
1
+ class String
2
+ def underscore
3
+ self.gsub(/::/, '/').
4
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
5
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
6
+ tr('-', '_').
7
+ downcase
8
+ end
9
+
10
+ def replace_tags(tags)
11
+ str = self
12
+ tags.each { |name, value|
13
+ str = str.gsub(%r(\$\{#{name.to_s}\})m, value)
14
+ }
15
+ str
16
+ end
17
+
18
+ def replace_tags!(tags)
19
+ tags.each { |name, value|
20
+ self.gsub!(%r(\$\{#{name.to_s}\})m, value)
21
+ }
22
+ self
23
+ end
24
+
25
+ # colorization
26
+ def colorize(color_code)
27
+ "\e[#{color_code}m#{self}\e[0m"
28
+ end
29
+
30
+ def red
31
+ colorize(31)
32
+ end
33
+
34
+ def green
35
+ colorize(32)
36
+ end
37
+
38
+ def yellow
39
+ colorize(33)
40
+ end
41
+
42
+ def blue
43
+ colorize(34)
44
+ end
45
+
46
+ def pink
47
+ colorize(35)
48
+ end
49
+
50
+ def light_blue
51
+ colorize(36)
52
+ end
53
+
54
+ end
@@ -0,0 +1,142 @@
1
+ require 'ostruct'
2
+
3
+ module Spacer
4
+ module CSharp
5
+ def self.count_bol_spaces_and_tabs(lines)
6
+ bol = OpenStruct.new
7
+ bol.tabs = 0
8
+ bol.spaces = 0
9
+ in_multi_line_string = false
10
+
11
+ for line in lines do
12
+ in_bol = true
13
+ i = 0
14
+ while i < line.length do
15
+ c = line[i]
16
+ c1 = i < line.length - 1 ? line[i + 1] : "\0"
17
+
18
+ if in_multi_line_string and c == "\"" and c1 != "\""
19
+ in_multi_line_string = false
20
+ elsif c == "@" and c1 == "\""
21
+ in_multi_line_string = true
22
+ i += 1
23
+ elsif in_bol and !in_multi_line_string and c == " "
24
+ bol.spaces += 1
25
+ elsif in_bol and !in_multi_line_string and c == "\t"
26
+ bol.tabs += 1
27
+ else
28
+ in_bol = false
29
+ end
30
+ i += 1
31
+ end
32
+ end
33
+
34
+ bol
35
+ end
36
+
37
+ def self.untabify(lines, tabsize)
38
+ # Expand tabs anywhere on a line, but not inside @"..." strings
39
+ in_multi_line_string = false
40
+
41
+ i = 0
42
+ while i < lines.length do
43
+ line = lines[i]
44
+ in_string = false
45
+ new_line = ""
46
+ j = 0
47
+
48
+ while j < line.length do
49
+ c_1 = j > 0 ? line[j - 1] : '\0'
50
+ c = line[j]
51
+ c1 = j < line.length - 1 ? line[j + 1] : '\0'
52
+
53
+ raise "line #{i + 1} has overlapping regular and multiline strings" if (in_string and in_multi_line_string)
54
+
55
+ if !in_multi_line_string and c == "\t"
56
+ # Add spaces to next tabstop
57
+ num_spaces = tabsize - (new_line.length % tabsize)
58
+
59
+ new_line += " " * num_spaces
60
+ elsif !in_multi_line_string and !in_string and c == "\""
61
+ in_string = true
62
+ new_line += c
63
+ elsif !in_multi_line_string and !in_string and c == "@" and c1 == "\""
64
+ in_multi_line_string = true
65
+ new_line += c
66
+ j += 1
67
+ new_line += c1
68
+ elsif in_string and c == "\"" and c_1 != "\\"
69
+ in_string = false
70
+ new_line += c
71
+ elsif in_multi_line_string and c == "\"" and c1 != "\""
72
+ in_multi_line_string = false
73
+ new_line += c
74
+ else
75
+ new_line += c
76
+ end
77
+
78
+ lines[i] = new_line
79
+ j += 1
80
+ end
81
+ i += 1
82
+ end
83
+ end
84
+
85
+ def self.tabify(lines, tabsize, round_down_spaces)
86
+ # Insert tabs for spaces, but only at the beginning of lines and not inside @"..." or "..." strings
87
+ in_multi_line_string = false
88
+ i = 0
89
+
90
+ while i < lines.length do
91
+ line = lines[i]
92
+ in_string = false
93
+ bol = true
94
+ num_bol_spaces = 0
95
+ new_line = ""
96
+ j = 0
97
+
98
+ while j < line.length do
99
+ c_1 = j > 0 ? line[j - 1] : "\0"
100
+ c = line[j]
101
+ c1 = j < line.length - 1 ? line[j + 1] : "\0"
102
+
103
+ if !in_string and !in_multi_line_string and bol and c == " "
104
+ # Just count the spaces
105
+ num_bol_spaces += 1
106
+ elsif !in_string and !in_multi_line_string and bol and c != " "
107
+ bol = false
108
+
109
+ new_line += "\t" * (num_bol_spaces / tabsize)
110
+
111
+ if !round_down_spaces
112
+ new_line += " " * (num_bol_spaces % tabsize)
113
+ end
114
+ # Process this character again as not BOL
115
+ j -= 1
116
+ elsif !in_multi_line_string and !in_string and c == '"'
117
+ in_string = true
118
+ new_line += c
119
+ elsif !in_multi_line_string and !in_string and c == "@" and c1 == "\""
120
+ in_multi_line_string = true
121
+ new_line += c
122
+ j += 1
123
+ new_line += c1
124
+ elsif in_string and c == "\"" and c_1 != "\\"
125
+ in_string = false
126
+ new_line += c
127
+ elsif in_multi_line_string and c == "\"" and c1 != "\""
128
+ in_multi_line_string = false
129
+ new_line += c
130
+ else
131
+ new_line += c
132
+ end
133
+
134
+ lines[i] = new_line
135
+ j += 1
136
+ end
137
+ i += 1
138
+ end
139
+ end
140
+
141
+ end
142
+ end
@@ -0,0 +1,85 @@
1
+ module Spacer
2
+ module Text
3
+ def self.count_bol_spaces_and_tabs(lines)
4
+ bol = OpenStruct.new
5
+ bol.spaces = 0
6
+ bol.tabs = 0
7
+
8
+ for line in lines do
9
+ for i in 0...line.length do
10
+ c = line[i]
11
+
12
+ if c == " "
13
+ bol.spaces += 1
14
+ elsif c == "\t"
15
+ bol.tabs += 1
16
+ else
17
+ break
18
+ end
19
+ end
20
+ end
21
+
22
+ bol
23
+ end
24
+
25
+ def self.untabify(lines, tabsize)
26
+ i = 0
27
+ while i < lines.length do
28
+ line = lines[i]
29
+ j = 0
30
+ new_line = ""
31
+
32
+ while j < line.length do
33
+ c = line[j]
34
+
35
+ if c == "\t"
36
+ num_spaces = tabsize - (new_line.length % tabsize)
37
+ new_line += " " * num_spaces
38
+ else
39
+ new_line += c
40
+ end
41
+ j += 1
42
+ end
43
+
44
+ lines[i] = new_line
45
+ i += 1
46
+ end
47
+ end
48
+
49
+ def self.tabify(lines, tabsize, round_down_spaces)
50
+ i = 0
51
+ while i < lines.length do
52
+ line = lines[i]
53
+ j = 0
54
+ bol = true
55
+ num_bol_spaces = 0
56
+ new_line = ""
57
+
58
+ while j < line.length do
59
+ c = line[j]
60
+
61
+ if bol and c == " "
62
+ num_bol_spaces += 1
63
+ elsif bol and c != " "
64
+ bol = false
65
+ new_line += "\t" * (num_bol_spaces / tabsize)
66
+
67
+ if !round_down_spaces
68
+ new_line += " " * (num_bol_spaces % tabsize)
69
+ end
70
+
71
+ new_line += c
72
+ else
73
+ new_line += c
74
+ end
75
+
76
+ j += 1
77
+ end
78
+
79
+ lines[i] = new_line
80
+ i += 1
81
+ end
82
+ end
83
+
84
+ end
85
+ end
data/lib/spacer.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'spacer/text'
2
+ require 'spacer/csharp'
@@ -0,0 +1,105 @@
1
+ <?xml version="1.0" encoding="UTF-8" ?>
2
+ <VersionConfig>
3
+ <FileType>
4
+ <Name>Ruby Files</Name>
5
+ <FileSpec>*.rb</FileSpec>
6
+ <Update>
7
+ <Search>(?'Before'\$VERSION=\')([0-9]+\.[0-9]+\.[0-9]+)-[0-9]+\.[0-9]+(?'After'\')</Search>
8
+ <Replace>${Before}${Major}.${Minor}.${Patch}-${Build}.${Revision}${After}</Replace>
9
+ </Update>
10
+ </FileType>
11
+ <FileType>
12
+ <Name>Version-in-a-text-file</Name>
13
+ <FileSpec>*.version.txt</FileSpec>
14
+ <Write>Release ${Major}.${Minor}.${Build}.${Revision}</Write>
15
+ </FileType>
16
+ <FileType>
17
+ <Name>Windows Manifest File</Name>
18
+ <FileSpec>WMManifest.xml</FileSpec>
19
+ <Update>
20
+ <Search>(?'Before'Version=")([0-9]+\.[0-9]+)(?'After'\.[0-9]+\.[0-9]+")</Search>
21
+ <Replace>${Before}${Major}.${Minor}${After}</Replace>
22
+ </Update>
23
+ </FileType>
24
+ <FileType>
25
+ <Name>C# Source</Name>
26
+ <FileSpec>*.cs</FileSpec>
27
+ <Update>
28
+ <Search>(?'Before'AssemblyVersion\(")([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(?'After'"\))</Search>
29
+ <Replace>${Before}${Major}.${Minor}.0.0${After}</Replace>
30
+ </Update>
31
+ <Update>
32
+ <Search>(?'Before'AssemblyFileVersion\(")([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(?'After'"\))</Search>
33
+ <Replace>${Before}${Major}.${Minor}.${Build}.${Revision}${After}</Replace>
34
+ </Update>
35
+ <Update>
36
+ <Search>(?'Before'AssemblyProduct\(")([^"]*)(?'After'"\))</Search>
37
+ <Replace>${Before}${Product}${After}</Replace>
38
+ </Update>
39
+ <Update>
40
+ <Search>(?'Before'AssemblyCopyright\(")([^"]*)(?'After'"\))</Search>
41
+ <Replace>${Before}${Copyright}${After}</Replace>
42
+ </Update>
43
+ <Update>
44
+ <Search>(?'Before'AssemblyCompany\(")([^"]*)(?'After'"\))</Search>
45
+ <Replace>${Before}${Company}${After}</Replace>
46
+ </Update>
47
+ </FileType>
48
+ <FileType>
49
+ <Name>Windows RC File</Name>
50
+ <FileSpec>*.rc</FileSpec>
51
+ <Update>
52
+ <Search>(?'Before'FILEVERSION )([0-9]+,[0-9]+,[0-9]+,[0-9]+)</Search>
53
+ <Replace>${Before}${Major},${Minor},${Build},${Revision}</Replace>
54
+ </Update>
55
+ <Update>
56
+ <Search>(?'Before'PRODUCTVERSION )([0-9]+,[0-9]+,[0-9]+,[0-9]+)</Search>
57
+ <Replace>${Before}${Major},${Minor},${Build},${Revision}</Replace>
58
+ </Update>
59
+ <Update>
60
+ <Search>(?'Before'"FileVersion",[ \t]*")([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(?'After'")</Search>
61
+ <Replace>${Before}${Major}.${Minor}.${Build}.${Revision}${After}</Replace>
62
+ </Update>
63
+ <Update>
64
+ <Search>(?'Before'"ProductVersion",[ \t]*")([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(?'After'")</Search>
65
+ <Replace>${Before}${Major}.${Minor}.${Build}.${Revision}${After}</Replace>
66
+ </Update>
67
+ </FileType>
68
+ <FileType>
69
+ <Name>WiX Files</Name>
70
+ <FileSpec>*.wxi</FileSpec>
71
+ <FileSpec>*.wxs</FileSpec>
72
+ <Update>
73
+ <Search>(?'Before'ProductVersion = ")([0-9]+\.[0-9]+)(?'After'")</Search>
74
+ <Replace>${Before}${Major}.${Minor}${After}</Replace>
75
+ </Update>
76
+ <Update>
77
+ <Search>(?'Before'ProductBuild = ")([0-9]+\.([0-9]|[1-9][0-9]))(?'After'")</Search>
78
+ <Replace>${Before}${Build}.${Revision}${After}</Replace>
79
+ </Update>
80
+ </FileType>
81
+ <FileType>
82
+ <Name>.NET Config Files</Name>
83
+ <FileSpec>*.config</FileSpec>
84
+ <Update>
85
+ <Search>(?'Before', +Version=)\d+\.\d+(?'After'\.0\.0 *,)</Search>
86
+ <Replace>${Before}${Major}.${Minor}${After}</Replace>
87
+ </Update>
88
+ </FileType>
89
+ <FileType>
90
+ <Name>Visual Studio Project Files</Name>
91
+ <FileSpec>*.csproj</FileSpec>
92
+ <Update>
93
+ <Search>(?'Before'&lt;OutputName&gt;" + projectName + @"_)([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(?'After'&lt;/OutputName&gt;)</Search>
94
+ <Replace>${Before}${Major}.${Minor}.${Build}.${Revision}${After}</Replace>
95
+ </Update>
96
+ </FileType>
97
+ <FileType>
98
+ <Name>VSIX Manifest</Name>
99
+ <FileSpec>*.vsixmanifest</FileSpec>
100
+ <Update>
101
+ <Search>(?'Before'&lt;Version&gt;)([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(?'After'&lt;/Version&gt;)</Search>
102
+ <Replace>${Before}${Major}.${Minor}.${Build}.${Revision}${After}</Replace>
103
+ </Update>
104
+ </FileType>
105
+ </VersionConfig>
@@ -0,0 +1,42 @@
1
+ require 'nokogiri'
2
+ require_relative '../core_ext.rb'
3
+
4
+ module Vamper
5
+ class VersionConfigFile
6
+
7
+ def self.get_default_file
8
+ File.join(File.dirname(__FILE__), 'default.version.config')
9
+ end
10
+
11
+ def initialize(io, tags)
12
+ doc = Nokogiri::XML(io)
13
+
14
+ @file_types = []
15
+ doc.xpath('/VersionConfig/FileType').each do |node|
16
+ file_type_struct = Struct.new(:name, :file_specs, :updates, :write)
17
+ search_replace_struct = Struct.new(:search, :replace)
18
+ file_type = file_type_struct.new
19
+ file_type.name = node.name
20
+ file_type.file_specs = node.xpath('FileSpec').map { |sub_node|
21
+ Regexp.new('^' + Regexp::escape(sub_node.text).gsub('\\*', '.*').gsub('\\?', '.') + '$')
22
+ }
23
+ update_node_set = node.xpath('Update')
24
+ if update_node_set
25
+ # Replace ${...} entries in the replace string with equivalent tags if available
26
+ file_type.updates = update_node_set.map { |sub_node|
27
+ s_and_r = search_replace_struct.new(
28
+ %r(#{sub_node.at_xpath('Search').text.gsub(/\(\?'(\w+)'/, '(?<\\1>')}),
29
+ sub_node.at_xpath('Replace').text.replace_tags(tags))
30
+ }
31
+ end
32
+ write_node = node.at_xpath('Write')
33
+ if write_node
34
+ file_type.write = write_node.text.replace_tags(tags)
35
+ end
36
+ @file_types.push(file_type)
37
+ end
38
+ end
39
+
40
+ attr_reader :file_types
41
+ end
42
+ end
@@ -0,0 +1,97 @@
1
+ require 'nokogiri'
2
+ require_relative '../core_ext.rb'
3
+
4
+ module Vamper
5
+ class BadVersionFile < StandardError; end
6
+
7
+ class VersionFile
8
+ attr_reader :tags
9
+
10
+ def initialize(io)
11
+ if io
12
+ @doc = Nokogiri::XML(io, &:noblanks)
13
+
14
+ unless @doc.root.name == 'Version'
15
+ raise BadVersionFile, 'Root element must be Version'
16
+ end
17
+ else
18
+ @doc = Nokogiri::XML::Document.new
19
+ @doc.root.add_child(Nokogiri::XML::Element.new('Version', @doc))
20
+ end
21
+
22
+ add_attribute @doc.root, :BuildValueType => :JDate
23
+ add_child_list_element @doc.root, :Files, :Tags
24
+ add_child_element tags_element,
25
+ :Major => 1, :Minor => 0, :Build => 0, :Patch => 0, :Revision => 0, :TimeZone => 'UTC'
26
+ add_child_element tags_element, {:StartYear => TZInfo::Timezone.get(self.time_zone).now.year}
27
+ end
28
+
29
+ def add_attribute(parent_node, attr_definitions)
30
+ attr_definitions.each { |attr_symbol, attr_default|
31
+ method_name = attr_symbol.to_s.underscore
32
+ unless parent_node[attr_symbol]
33
+ parent_node[attr_symbol] = attr_default
34
+ end
35
+ define_singleton_method(method_name.to_sym) {
36
+ parent_node[attr_symbol].to_sym
37
+ }
38
+ define_singleton_method((method_name + '=').to_sym) { |value|
39
+ parent_node[attr_symbol] = value.to_s
40
+ }
41
+ }
42
+ end
43
+
44
+ def add_child_list_element(parent_element, *element_symbols)
45
+ element_symbols.each { |element_symbol|
46
+ name = element_symbol.to_s
47
+ elem = parent_element.at(name)
48
+ unless elem
49
+ elem = parent_element.add_child(Nokogiri::XML::Element.new(name, @doc))
50
+ end
51
+
52
+ method_name = name.underscore + '_element'
53
+ define_singleton_method(method_name.to_sym) {
54
+ elem
55
+ }
56
+ }
57
+ end
58
+
59
+ def add_child_element(parent_element, element_definitions)
60
+ element_definitions.each { |element_symbol, element_default|
61
+ name = element_symbol.to_s
62
+ elem = parent_element.at(name)
63
+ unless elem
64
+ elem = parent_element.add_child(Nokogiri::XML::Element.new(name, @doc))
65
+ elem.content = element_default.to_s
66
+ end
67
+
68
+ method_name = name.underscore
69
+ case element_default
70
+ when Fixnum
71
+ define_singleton_method(method_name.to_sym) {
72
+ Integer(elem.content)
73
+ }
74
+ when String
75
+ define_singleton_method(method_name.to_sym) {
76
+ elem.content.to_s
77
+ }
78
+ end
79
+ define_singleton_method((method_name + '=').to_sym) { |value|
80
+ elem.content = value.to_s
81
+ }
82
+ }
83
+ end
84
+
85
+ def write_to(io)
86
+ @doc.write_xml_to(io, :indent_text => ' ', :indent => 2)
87
+ end
88
+
89
+ def tags
90
+ Hash[tags_element.children.select {|node| node.name != 'text'}.map {|node| [node.name.to_sym, node.content]}]
91
+ end
92
+ def files
93
+ files_element.children.select {|node| node.name != 'text'}.map {|node| node.content}
94
+ end
95
+
96
+ end
97
+ end
data/lib/vamper.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'vamper/version_file'
2
+ require 'vamper/version_config_file'
3
+ require 'core_ext.rb'
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: code-tools
3
+ version: !ruby/object:Gem::Version
4
+ version: 5.0.0
5
+ platform: ruby
6
+ authors:
7
+ - John Lyon-smith
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-01-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: tzinfo
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: nokogiri
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: methadone
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.9'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.9'
55
+ description: Tools for source code maintenance, including version stamping, line endings
56
+ and tab/space conversion.
57
+ email: john@jamoki.com
58
+ executables:
59
+ - code-tools
60
+ - ender
61
+ - spacer
62
+ - vamper
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - bin/code-tools
67
+ - bin/ender
68
+ - bin/spacer
69
+ - bin/vamper
70
+ - lib/core_ext.rb
71
+ - lib/spacer.rb
72
+ - lib/spacer/csharp.rb
73
+ - lib/spacer/text.rb
74
+ - lib/vamper.rb
75
+ - lib/vamper/default.version.config
76
+ - lib/vamper/version_config_file.rb
77
+ - lib/vamper/version_file.rb
78
+ homepage: http://rubygems.org/gems/code_tools
79
+ licenses:
80
+ - MIT
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '2.0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.4.5
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: Source code tools
102
+ test_files: []