vmlib 1.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 +7 -0
- data/Gemfile +5 -0
- data/README.md +80 -0
- data/Rakefile +24 -0
- data/Version +1 -0
- data/bin/vmlib +156 -0
- data/lib/vmlib/base.rb +214 -0
- data/lib/vmlib/bump.rb +93 -0
- data/lib/vmlib/compare.rb +107 -0
- data/lib/vmlib/errors.rb +55 -0
- data/lib/vmlib/file.rb +106 -0
- data/lib/vmlib/format.rb +94 -0
- data/lib/vmlib/issue.txt +13 -0
- data/lib/vmlib/parse.rb +216 -0
- data/lib/vmlib/source.rb +65 -0
- data/lib/vmlib/version.rb +12 -0
- data/lib/vmlib.rb +23 -0
- data/test/test_version_basic.rb +113 -0
- data/vmlib.gemspec +26 -0
- metadata +91 -0
data/lib/vmlib/errors.rb
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
# VMLib exceptions
|
|
3
|
+
###############################################################################
|
|
4
|
+
# Copyright (C) 2013 Nirenjan Krishnan
|
|
5
|
+
# All rights reserved.
|
|
6
|
+
###############################################################################
|
|
7
|
+
|
|
8
|
+
;
|
|
9
|
+
|
|
10
|
+
module VMLib
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# This is a namespace for errors that can be thrown by VMLib
|
|
14
|
+
module Errors
|
|
15
|
+
|
|
16
|
+
# Base class for all VMLib exceptions
|
|
17
|
+
class VMLibError < ::RuntimeError
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Thrown if release type doesn't match with requested parameter
|
|
21
|
+
class NoVersionError < VMLibError
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Thrown if bump operation cannot be performed
|
|
25
|
+
class BumpError < VMLibError
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Thrown if initialization fails
|
|
29
|
+
class InitError < VMLibError
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Thrown if parsing fails
|
|
33
|
+
class ParseError < VMLibError
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Thrown if assigning an invalid value
|
|
37
|
+
class AssignError < VMLibError
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Thrown if the API receives invalid parameters
|
|
41
|
+
class ParameterError < VMLibError
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Thrown if there's an issue with the path for the version file
|
|
45
|
+
class PathError < VMLibError
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Thrown if there's an issue with the version file itself
|
|
49
|
+
class VersionFileError < VMLibError
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
|
data/lib/vmlib/file.rb
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
# VMLib file manager
|
|
3
|
+
###############################################################################
|
|
4
|
+
# Copyright (C) 2013 Nirenjan Krishnan
|
|
5
|
+
# All rights reserved.
|
|
6
|
+
###############################################################################
|
|
7
|
+
|
|
8
|
+
;
|
|
9
|
+
|
|
10
|
+
module VMLib
|
|
11
|
+
|
|
12
|
+
# This is the file class for handling VMLib version files
|
|
13
|
+
class File
|
|
14
|
+
|
|
15
|
+
# Default file name of 'Version'
|
|
16
|
+
FILE_NAME = 'Version'
|
|
17
|
+
|
|
18
|
+
# Create a new file object with the specified filename. If the filename
|
|
19
|
+
# is not specified, it reverts to the default
|
|
20
|
+
def initialize(filename = nil)
|
|
21
|
+
@filename ||= FILE_NAME
|
|
22
|
+
@dir = nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Search the current and all parent folders for a version file
|
|
26
|
+
# Raises an error if it cannot find any up to the root.
|
|
27
|
+
def find_file(dir = nil)
|
|
28
|
+
dir ||= ::Dir.pwd
|
|
29
|
+
raise Errors::PathError unless ::File.directory?(dir)
|
|
30
|
+
path = ::File.join(dir, @filename)
|
|
31
|
+
|
|
32
|
+
::Dir.chdir(dir) do
|
|
33
|
+
while !::File.exists?(path) do
|
|
34
|
+
if (::File.dirname(path).match(/^(\w:\/|\/)$/i))
|
|
35
|
+
raise Errors::NoVersionError, "#{dir} is not versioned"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
path = ::File.join(::File.dirname(path), '..')
|
|
39
|
+
path = ::File.expand_path(path)
|
|
40
|
+
#puts "vmlib: looking at path #{path}"
|
|
41
|
+
path = ::File.join(path, @filename)
|
|
42
|
+
end
|
|
43
|
+
@dir = path
|
|
44
|
+
return path
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Read the version file and return the parsed version data
|
|
49
|
+
def read(dir = nil)
|
|
50
|
+
path = find_file(dir)
|
|
51
|
+
|
|
52
|
+
if ::File.readable?(path)
|
|
53
|
+
# Read
|
|
54
|
+
verdata = Version.new
|
|
55
|
+
verdata.parse ::File.read(path)
|
|
56
|
+
else
|
|
57
|
+
raise Errors::VersionFileError, "unable to read #{path}"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
return verdata
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Write the specfied version into the version file
|
|
64
|
+
def write(version, dir = nil)
|
|
65
|
+
path = find_file(dir)
|
|
66
|
+
|
|
67
|
+
unless version.is_a? Version
|
|
68
|
+
raise Errors::ParameterError, "invalid version #{version}"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
if ::File.writable?(path)
|
|
72
|
+
# Write
|
|
73
|
+
::File.write(path, version.to_s + "\n")
|
|
74
|
+
else
|
|
75
|
+
raise Errors::VersionFileError, "unable to write #{path}"
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Create a new version file for the current (or specified) folder.
|
|
80
|
+
# If it already exists, then throw an error
|
|
81
|
+
def create(name = '', dir = nil)
|
|
82
|
+
# Make sure that the directory isn't versioned already
|
|
83
|
+
begin
|
|
84
|
+
path = find_file(dir)
|
|
85
|
+
rescue Errors::NoVersionError
|
|
86
|
+
# We are good to go
|
|
87
|
+
else
|
|
88
|
+
# Raise error that it's already versioned
|
|
89
|
+
raise Errors::VersionFileError, "version already exists at #{path}"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
dir ||= ::Dir.pwd
|
|
93
|
+
raise Errors::PathError unless ::File.directory?(dir)
|
|
94
|
+
path = ::File.join(dir, @filename)
|
|
95
|
+
|
|
96
|
+
::File.open(path, "w") do |file|
|
|
97
|
+
version = Version.new(name)
|
|
98
|
+
file.write version.to_s + "\n"
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
end
|
data/lib/vmlib/format.rb
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
# VMLib formatter
|
|
3
|
+
###############################################################################
|
|
4
|
+
# Copyright (C) 2013 Nirenjan Krishnan
|
|
5
|
+
# All rights reserved.
|
|
6
|
+
###############################################################################
|
|
7
|
+
|
|
8
|
+
;
|
|
9
|
+
|
|
10
|
+
module VMLib
|
|
11
|
+
|
|
12
|
+
class Version
|
|
13
|
+
|
|
14
|
+
# Default tag format for version control systems
|
|
15
|
+
TAG_FORMAT = 'v%M.%m.%p%r%b'
|
|
16
|
+
|
|
17
|
+
# Display the version in the specified format
|
|
18
|
+
# Input: Format string
|
|
19
|
+
# %n - name
|
|
20
|
+
# %M - major version number
|
|
21
|
+
# %m - minor version number
|
|
22
|
+
# %p - patch number
|
|
23
|
+
# %r - prerelease
|
|
24
|
+
# %b - build number
|
|
25
|
+
def format(fstr)
|
|
26
|
+
if @name.empty?
|
|
27
|
+
fstr = fstr.gsub('%n', '')
|
|
28
|
+
else
|
|
29
|
+
fstr = fstr.gsub('%n', @name.to_s + ' ')
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Match the major version
|
|
33
|
+
match = /%(\d*)M/.match(fstr)
|
|
34
|
+
fstr = fstr.gsub(/%(\d*)M/, "%0#{$1}d" % @major)
|
|
35
|
+
|
|
36
|
+
# Match the minor version
|
|
37
|
+
match = /%(\d*)m/.match(fstr)
|
|
38
|
+
fstr = fstr.gsub(/%(\d*)m/, "%0#{$1}d" % @minor)
|
|
39
|
+
|
|
40
|
+
# Match the patch version
|
|
41
|
+
match = /%(\d*)p/.match(fstr)
|
|
42
|
+
fstr = fstr.gsub(/%(\d*)p/, "%0#{$1}d" % @patch)
|
|
43
|
+
|
|
44
|
+
if (@reltype == :rel_type_final) or
|
|
45
|
+
(@reltype == :rel_type_custom and @relcustom.length == 0)
|
|
46
|
+
fstr = fstr.gsub('%r', '')
|
|
47
|
+
else
|
|
48
|
+
fstr = case @reltype
|
|
49
|
+
when :rel_type_dev
|
|
50
|
+
fstr.gsub('%r', "-#{@devnum}")
|
|
51
|
+
when :rel_type_alpha
|
|
52
|
+
fstr.gsub('%r', "-a.#{@alphanum}")
|
|
53
|
+
when :rel_type_beta
|
|
54
|
+
fstr.gsub('%r', "-b.#{@betanum}")
|
|
55
|
+
when :rel_type_rc
|
|
56
|
+
fstr.gsub('%r', "-rc.#{@rcnum}")
|
|
57
|
+
when :rel_type_custom
|
|
58
|
+
fstr.gsub('%r', '-' + @relcustom.join('.'))
|
|
59
|
+
else
|
|
60
|
+
fstr.gsub('%r', '')
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
if (@buildtype == :bld_type_final) or
|
|
65
|
+
(@buildtype == :bld_type_custom and @buildcustom.length == 0)
|
|
66
|
+
fstr = fstr.gsub('%b', '')
|
|
67
|
+
else
|
|
68
|
+
fstr = case @buildtype
|
|
69
|
+
when :bld_type_custom
|
|
70
|
+
fstr.gsub('%b', '+' + @buildcustom.join('.'))
|
|
71
|
+
else
|
|
72
|
+
fstr.gsub('%b', '')
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
fstr
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Display a version tag suitable for use in tagging releases
|
|
80
|
+
# in the user's version control system
|
|
81
|
+
def tag
|
|
82
|
+
format TAG_FORMAT
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Display the version information as a string
|
|
86
|
+
def to_s
|
|
87
|
+
format "%n%M.%m.%p%r%b"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
end
|
data/lib/vmlib/issue.txt
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
In paragraphs 10 and 11, the following text is present.
|
|
2
|
+
|
|
3
|
+
> Identifiers MUST be comprised of only ASCII alphanumerics and dash [0-9A-Za-z-].
|
|
4
|
+
|
|
5
|
+
However, it is unclear if an identifier can begin or end with a dash, or have multiple dashes in sequence. If that is allowed, then in theory, we could have identifiers like the following.
|
|
6
|
+
|
|
7
|
+
1.0.0--+-
|
|
8
|
+
1.0.0-----+----
|
|
9
|
+
1.0.0--alpha--.-1-
|
|
10
|
+
1.0.0--beta-.-2-+--build-256--
|
|
11
|
+
1.0.0+-256
|
|
12
|
+
|
|
13
|
+
My understanding of the text indicates that this is not disallowed, but in my opinion, we should have the text
|
data/lib/vmlib/parse.rb
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
# VMLib parser
|
|
3
|
+
###############################################################################
|
|
4
|
+
# Copyright (C) 2013 Nirenjan Krishnan
|
|
5
|
+
# All rights reserved.
|
|
6
|
+
###############################################################################
|
|
7
|
+
|
|
8
|
+
;
|
|
9
|
+
|
|
10
|
+
module VMLib
|
|
11
|
+
|
|
12
|
+
class Version
|
|
13
|
+
|
|
14
|
+
# The parse functions are all marked as private
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
# Regular expression format to understand the release and build formats.
|
|
18
|
+
#
|
|
19
|
+
# Acceptable formats:
|
|
20
|
+
# alpha.1.4
|
|
21
|
+
# beta.1.4
|
|
22
|
+
# 6.2.8
|
|
23
|
+
# 1
|
|
24
|
+
# build-256.2013-01-04T16-40Z
|
|
25
|
+
#
|
|
26
|
+
# These fields consist of dot-separated identifiers, and these identifiers
|
|
27
|
+
# may contain only alphanumeric characters and hyphens.
|
|
28
|
+
#
|
|
29
|
+
# Fields consisting of only digits will be interpreted as numeric and
|
|
30
|
+
# leading zeroes will be stripped.
|
|
31
|
+
SPECIAL_REGEX = /^[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*/
|
|
32
|
+
|
|
33
|
+
# Regular expression to understand the version format.
|
|
34
|
+
#
|
|
35
|
+
# Acceptable formats:
|
|
36
|
+
# 1.078.2
|
|
37
|
+
# v1.30.4908
|
|
38
|
+
# version 2.4.875
|
|
39
|
+
#
|
|
40
|
+
# Leading zeroes will be stripped in any numeric field, therefore, the
|
|
41
|
+
# version 1.078.2 would be treated the same as 1.78.2
|
|
42
|
+
VER_REGEX = /^(?:v|version )?(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)/
|
|
43
|
+
|
|
44
|
+
# Regular expression format to retrieve the name. Names may consist of
|
|
45
|
+
# any combination of any alphanumeric character, underscores and hyphens.
|
|
46
|
+
NAME_REGEX = /^(?<name>[0-9A-Za-z_-]+)\s+/
|
|
47
|
+
|
|
48
|
+
def convert_to_integer(array)
|
|
49
|
+
array.kind_of? Array or
|
|
50
|
+
raise Errors::VMLibError, "not an array: #{array}"
|
|
51
|
+
|
|
52
|
+
for i in (0...array.length)
|
|
53
|
+
array[i].to_s.match(/^\d+$/) and array[i] = array[i].to_i
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def parse_release(str)
|
|
58
|
+
match = SPECIAL_REGEX.match(str)
|
|
59
|
+
if match
|
|
60
|
+
# OK, we have a prerelease match, now parse it to determine
|
|
61
|
+
# the release type
|
|
62
|
+
@relcustom = match[0].split '.'
|
|
63
|
+
rel = @relcustom[0]
|
|
64
|
+
case rel
|
|
65
|
+
|
|
66
|
+
# Development version 1.0.0-0, 1.0.0-1, 1.0.0-2, etc.
|
|
67
|
+
when /^\d+$/
|
|
68
|
+
if @relcustom.length == 1
|
|
69
|
+
@reltype = :rel_type_dev
|
|
70
|
+
@devnum = rel.to_i
|
|
71
|
+
else
|
|
72
|
+
@reltype = :rel_type_custom
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Alpha version 1.0.0-a.1, 1.0.0-alpha.2, etc.
|
|
76
|
+
when /^(a|alpha)$/
|
|
77
|
+
if @relcustom.length == 2 && @relcustom[1].match(/^\d+$/)
|
|
78
|
+
@reltype = :rel_type_alpha
|
|
79
|
+
@alphanum = @relcustom[1].to_i
|
|
80
|
+
else
|
|
81
|
+
@reltype = :rel_type_custom
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Beta version 1.0.0-b.1, 1.0.0-beta.2, etc.
|
|
85
|
+
when /^(b|beta)$/
|
|
86
|
+
if @relcustom.length == 2 && @relcustom[1].match(/^\d+$/)
|
|
87
|
+
@reltype = :rel_type_beta
|
|
88
|
+
@betanum = @relcustom[1].to_i
|
|
89
|
+
else
|
|
90
|
+
@reltype = :rel_type_custom
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Release Candidate version 1.0.0-rc.1, 1.0.0-rc.2, etc.
|
|
94
|
+
when /^rc$/
|
|
95
|
+
if @relcustom.length == 2 && @relcustom[1].match(/^\d+$/)
|
|
96
|
+
@reltype = :rel_type_rc
|
|
97
|
+
@rcnum = @relcustom[1].to_i
|
|
98
|
+
else
|
|
99
|
+
@reltype = :rel_type_custom
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
else
|
|
103
|
+
@reltype = :rel_type_custom
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Done parsing, clear the relcustom array if it's not a custom type
|
|
107
|
+
@relcustom = [] unless @reltype == :rel_type_custom
|
|
108
|
+
convert_to_integer(@relcustom)
|
|
109
|
+
else # if !match
|
|
110
|
+
# It may be an empty string, so set the reltype to final in that case
|
|
111
|
+
if str.empty?
|
|
112
|
+
match = nil
|
|
113
|
+
@reltype = :rel_type_final
|
|
114
|
+
else
|
|
115
|
+
raise Errors::ParseError, "unrecognized prerelease '#{str}'"
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
return match
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def parse_build(str)
|
|
123
|
+
match = SPECIAL_REGEX.match(str)
|
|
124
|
+
if match
|
|
125
|
+
# OK, we have a build match, now parse it to determine
|
|
126
|
+
# the release type
|
|
127
|
+
# Currently, only supports :bld_type_custom
|
|
128
|
+
@buildcustom = match[0].split '.'
|
|
129
|
+
@buildtype = :bld_type_custom
|
|
130
|
+
|
|
131
|
+
# Done parsing, clear the array if it's not a custom type
|
|
132
|
+
@buildcustom = [] unless @buildtype == :bld_type_custom
|
|
133
|
+
convert_to_integer(@buildcustom)
|
|
134
|
+
else # if !match
|
|
135
|
+
# It may be an empty string, so set the buildtype to final in that case
|
|
136
|
+
if str.empty?
|
|
137
|
+
match = nil
|
|
138
|
+
@buildtype = :bld_type_final
|
|
139
|
+
else
|
|
140
|
+
raise Errors::ParseError, "unrecognized build '#{str}'"
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
return match
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# With the exception of the root parse function
|
|
148
|
+
public
|
|
149
|
+
|
|
150
|
+
def parse(ver)
|
|
151
|
+
unless ver.kind_of? String
|
|
152
|
+
raise Errors::ParameterError, "expected a string to be parsed"
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Chop off any trailing newlines
|
|
156
|
+
ver.chomp!
|
|
157
|
+
|
|
158
|
+
# Match the name
|
|
159
|
+
match = NAME_REGEX.match(ver)
|
|
160
|
+
if match
|
|
161
|
+
@name = match[:name]
|
|
162
|
+
ver = ver.sub(NAME_REGEX, '')
|
|
163
|
+
#else
|
|
164
|
+
# Sometimes we may not get a name to be parsed. If that's the case
|
|
165
|
+
# then simply ignore it.
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Match the major, minor and patch versions
|
|
169
|
+
match = VER_REGEX.match(ver)
|
|
170
|
+
if match
|
|
171
|
+
@major = match[:major].to_i
|
|
172
|
+
@minor = match[:minor].to_i
|
|
173
|
+
@patch = match[:patch].to_i
|
|
174
|
+
ver = ver.sub(VER_REGEX, '')
|
|
175
|
+
else
|
|
176
|
+
raise Errors::ParseError, "unrecognized version format '#{ver}'"
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# See if we have a prerelease version (begins with a -)
|
|
180
|
+
if ver =~ /^-/
|
|
181
|
+
ver = ver.sub(/^-/, '')
|
|
182
|
+
|
|
183
|
+
match = parse_release(ver)
|
|
184
|
+
if match
|
|
185
|
+
# Delete the matched data
|
|
186
|
+
ver = ver.sub(SPECIAL_REGEX, '')
|
|
187
|
+
end
|
|
188
|
+
else # if ver !~ /^-/
|
|
189
|
+
@reltype = :rel_type_final
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# See if we have a build version (begins with a +)
|
|
193
|
+
if ver =~ /^\+/
|
|
194
|
+
ver = ver.sub(/^\+/, '')
|
|
195
|
+
|
|
196
|
+
match = parse_build(ver)
|
|
197
|
+
if match
|
|
198
|
+
# Delete the matched data
|
|
199
|
+
ver = ver.sub(SPECIAL_REGEX, '')
|
|
200
|
+
end
|
|
201
|
+
else # if ver !~ /^\+/
|
|
202
|
+
@buildtype = :bld_type_final
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# By now, ver should be empty. Raise an error if this is not the case
|
|
206
|
+
unless ver.empty?
|
|
207
|
+
raise Errors::ParseError, "unrecognized version format '#{ver}'"
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
true
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
end
|
data/lib/vmlib/source.rb
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
# VMLib source editor
|
|
3
|
+
###############################################################################
|
|
4
|
+
# Copyright (C) 2013 Nirenjan Krishnan
|
|
5
|
+
# All rights reserved.
|
|
6
|
+
###############################################################################
|
|
7
|
+
|
|
8
|
+
;
|
|
9
|
+
|
|
10
|
+
module VMLib
|
|
11
|
+
|
|
12
|
+
# This is the class for updating source files with the new version
|
|
13
|
+
class Source
|
|
14
|
+
|
|
15
|
+
# Set up the tree to find the root of the source repository
|
|
16
|
+
def initialize(dir = nil)
|
|
17
|
+
# Find the primary version file and get the root path
|
|
18
|
+
version = File.new.find_file(dir)
|
|
19
|
+
root = ::File.dirname(version)
|
|
20
|
+
|
|
21
|
+
# Find all files below the root which have the filename
|
|
22
|
+
# beginning with 'version'
|
|
23
|
+
@files = ::Dir.glob("#{root}/**/version*")
|
|
24
|
+
@files.delete_if {|f| ! ::File.file? f }
|
|
25
|
+
|
|
26
|
+
# Read the primary version file and get the version string from it
|
|
27
|
+
verdata = ::File.read(version)
|
|
28
|
+
v = Version.new
|
|
29
|
+
v.parse verdata
|
|
30
|
+
@verstring = v.format '"%M.%m.%p%r%b"'
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Update the specified file
|
|
34
|
+
def update_file (f)
|
|
35
|
+
fdata = ::File.read(f).split("\n")
|
|
36
|
+
|
|
37
|
+
for i in (0...fdata.length)
|
|
38
|
+
# Check for a version string
|
|
39
|
+
# VERSION ... "<version string>"
|
|
40
|
+
line = fdata[i]
|
|
41
|
+
|
|
42
|
+
if (line =~ /VERSION.*"\d+\.\d+\.\d+[^"]*"/)
|
|
43
|
+
puts "updating line #{i} in #{f}..."
|
|
44
|
+
puts " old: #{line}"
|
|
45
|
+
fdata[i] = line.gsub(/"\d+\.\d+\.\d+[^"]*"/, @verstring)
|
|
46
|
+
puts " new: #{fdata[i]}"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# For whatever reason, the split deletes the last entry and leaves
|
|
51
|
+
# us without a newline at the end of the file. Make sure that we
|
|
52
|
+
# do insert a newline at the end of the file.
|
|
53
|
+
::File.write(f, fdata.join("\n") + "\n")
|
|
54
|
+
end
|
|
55
|
+
private :update_file
|
|
56
|
+
|
|
57
|
+
# Update all the source files containing the version
|
|
58
|
+
def update
|
|
59
|
+
@files.each {|f| update_file(f) }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
# VMLib version information
|
|
3
|
+
###############################################################################
|
|
4
|
+
# Copyright (C) 2013 Nirenjan Krishnan
|
|
5
|
+
# All rights reserved.
|
|
6
|
+
###############################################################################
|
|
7
|
+
|
|
8
|
+
module VMLib
|
|
9
|
+
|
|
10
|
+
VERSION = "1.0.0" #:nodoc:
|
|
11
|
+
|
|
12
|
+
end
|
data/lib/vmlib.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
# VMLib library file
|
|
3
|
+
###############################################################################
|
|
4
|
+
# Copyright (C) 2013 Nirenjan Krishnan
|
|
5
|
+
# All rights reserved.
|
|
6
|
+
###############################################################################
|
|
7
|
+
|
|
8
|
+
# Version processing
|
|
9
|
+
require 'vmlib/base'
|
|
10
|
+
require 'vmlib/bump'
|
|
11
|
+
require 'vmlib/errors'
|
|
12
|
+
require 'vmlib/compare'
|
|
13
|
+
require 'vmlib/parse'
|
|
14
|
+
require 'vmlib/format'
|
|
15
|
+
|
|
16
|
+
# File processing
|
|
17
|
+
require 'vmlib/file'
|
|
18
|
+
|
|
19
|
+
# Gem version
|
|
20
|
+
require 'vmlib/version'
|
|
21
|
+
|
|
22
|
+
# Source file processing
|
|
23
|
+
require 'vmlib/source'
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
###############################################################################
|
|
2
|
+
# VMLib basic version test cases
|
|
3
|
+
###############################################################################
|
|
4
|
+
# Copyright (C) 2013 Nirenjan Krishnan
|
|
5
|
+
# All rights reserved.
|
|
6
|
+
###############################################################################
|
|
7
|
+
|
|
8
|
+
require 'test/unit'
|
|
9
|
+
require 'vmlib'
|
|
10
|
+
|
|
11
|
+
module VMLib
|
|
12
|
+
|
|
13
|
+
module Tests #:nodoc:
|
|
14
|
+
|
|
15
|
+
class TestBasicVersion < ::Test::Unit::TestCase #:nodoc:
|
|
16
|
+
|
|
17
|
+
# Test the default value when a new version is created
|
|
18
|
+
def test_default_value
|
|
19
|
+
version = VMLib::Version.new
|
|
20
|
+
|
|
21
|
+
assert_equal '0.0.0-0', version.to_s
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Test the version with a different version number
|
|
26
|
+
def test_custom_version
|
|
27
|
+
version = VMLib::Version.new('SomeProject', 1, 1, 0, 'a.1', 'b.20')
|
|
28
|
+
assert_equal 'SomeProject 1.1.0-a.1+b.20', version.to_s
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# Test setting the version record fields individually
|
|
33
|
+
def test_version_fields
|
|
34
|
+
version = VMLib::Version.new
|
|
35
|
+
assert_equal '0.0.0-0', version.to_s
|
|
36
|
+
|
|
37
|
+
version.major = 1
|
|
38
|
+
assert_equal '1.0.0-0', version.to_s
|
|
39
|
+
|
|
40
|
+
version.minor = 2
|
|
41
|
+
assert_equal '1.2.0-0', version.to_s
|
|
42
|
+
|
|
43
|
+
version.patch = 3
|
|
44
|
+
assert_equal '1.2.3-0', version.to_s
|
|
45
|
+
|
|
46
|
+
version.name = 'FooBar'
|
|
47
|
+
assert_equal 'FooBar 1.2.3-0', version.to_s
|
|
48
|
+
|
|
49
|
+
version.prerelease = ''
|
|
50
|
+
assert_equal 'FooBar 1.2.3', version.to_s
|
|
51
|
+
|
|
52
|
+
version.build = 'build.20'
|
|
53
|
+
assert_equal 'FooBar 1.2.3+build.20', version.to_s
|
|
54
|
+
|
|
55
|
+
version.prerelease = 'alpha.1'
|
|
56
|
+
assert_equal 'FooBar 1.2.3-a.1+build.20', version.to_s
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# Test the prerelease parser and formatter
|
|
62
|
+
def test_prerelease
|
|
63
|
+
version = VMLib::Version.new
|
|
64
|
+
version.prerelease = '1'
|
|
65
|
+
assert_equal '0.0.0-1', version.to_s
|
|
66
|
+
|
|
67
|
+
version.prerelease = 'a.2'
|
|
68
|
+
assert_equal '0.0.0-a.2', version.to_s
|
|
69
|
+
|
|
70
|
+
# Test that the string alpha gets interpreted as 'a'
|
|
71
|
+
version.prerelease = 'alpha.3'
|
|
72
|
+
assert_equal '0.0.0-a.3', version.to_s
|
|
73
|
+
|
|
74
|
+
# Test that a non-standard alpha gets treated as a custom field
|
|
75
|
+
version.prerelease = 'alpha.1.2'
|
|
76
|
+
assert_equal '0.0.0-alpha.1.2', version.to_s
|
|
77
|
+
|
|
78
|
+
version.prerelease = 'alpha.a1'
|
|
79
|
+
assert_equal '0.0.0-alpha.a1', version.to_s
|
|
80
|
+
|
|
81
|
+
version.prerelease = 'b.4'
|
|
82
|
+
assert_equal '0.0.0-b.4', version.to_s
|
|
83
|
+
|
|
84
|
+
# Test that the string beta gets interpreted as 'b'
|
|
85
|
+
version.prerelease = 'beta.3'
|
|
86
|
+
assert_equal '0.0.0-b.3', version.to_s
|
|
87
|
+
|
|
88
|
+
# Test that a non-standard beta gets treated as a custom field
|
|
89
|
+
version.prerelease = 'beta.a2'
|
|
90
|
+
assert_equal '0.0.0-beta.a2', version.to_s
|
|
91
|
+
|
|
92
|
+
version.prerelease = 'beta.1.2'
|
|
93
|
+
assert_equal '0.0.0-beta.1.2', version.to_s
|
|
94
|
+
|
|
95
|
+
version.prerelease = 'rc.1'
|
|
96
|
+
assert_equal '0.0.0-rc.1', version.to_s
|
|
97
|
+
|
|
98
|
+
# Test that an unrecognized format still gets stored
|
|
99
|
+
version.prerelease = 'foo.bar.baz'
|
|
100
|
+
assert_equal '0.0.0-foo.bar.baz', version.to_s
|
|
101
|
+
|
|
102
|
+
# Verify that an empty pre-release gets treated as a final release
|
|
103
|
+
version.prerelease = ''
|
|
104
|
+
assert_equal '0.0.0', version.to_s
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
end
|