Module: RightDevelop::Utility::Versioning

Defined in:
lib/right_develop/utility/versioning.rb

Constant Summary collapse

BUILD_VERSION_REGEX =
/^(\d)+\.(\d)+\.(\d)+$/
DEFAULT_WINDOWS_MODULE_VERSION =
"1.0.0.1"
'2010-2013'

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.is_valid_build_version?(version) ⇒ Boolean

Determines if version string is valid for building purposes.

Returns:

  • (Boolean)


36
37
38
# File 'lib/right_develop/utility/versioning.rb', line 36

def is_valid_build_version?(version)
  return !!BUILD_VERSION_REGEX.match(version)
end

.parse_build_version(version) ⇒ Array

Parses the given version string into numeric values.

Parameters

Return

Parameters:

  • version (String)

Returns:

  • (Array)

    numeric values



47
48
49
50
51
52
# File 'lib/right_develop/utility/versioning.rb', line 47

def parse_build_version(version)
  unless matched = BUILD_VERSION_REGEX.match(version)
    raise ArgumentError.new("Invalid version #{version.inspect}")
  end
  return matched[1..-1].map { |s| s.to_i }
end

Instance Method Details

#generate_guidObject

Generates a new GUID in Windows registry format (as expected by Microsoft-style source files that contain a GUID).

Return

guid(String)

a new guid



175
176
177
178
179
180
# File 'lib/right_develop/utility/versioning.rb', line 175

def generate_guid
  result = ::SecureRandom.random_bytes(16)
  a, b, c, d, e, f, g, h = result.unpack('SSSSSSSS')
  guid = sprintf('{%04X%04X-%04X-%04X-%04X-%04X%04X%04X}', a, b, c, d, e, f, g, h)
  guid
end

#replace_in_file(file_path, replacements) ⇒ Object

Replaces the given regular exressions in the given file, saving changes only if necessary.

Parameters

file_path(string)

path to text file which may or may not contain strings to replace

replacements(Hash)

map of regular expressions to literal replacement text



161
162
163
164
165
166
167
168
# File 'lib/right_develop/utility/versioning.rb', line 161

def replace_in_file(file_path, replacements)
  text = ::File.read(file_path)
  changed = nil
  replacements.each_pair do |pattern, value|
    changed = text.gsub!(pattern, value) || changed
  end
  ::File.open(file_path, 'w') { |f| f.write(text) } if changed
end

#restore_default_version(base_dir_path) ⇒ TrueClass

Restores the default version string in all modules to make files appear unchanged to source control.

Return

Returns:

  • (TrueClass)

    always true



65
66
67
68
# File 'lib/right_develop/utility/versioning.rb', line 65

def restore_default_version(base_dir_path)
  set_version_for_modules(base_dir_path, version_string = nil)
  true
end

#set_version_for_modules(base_dir_path, version_string = nil) ⇒ TrueClass

Sets the given version string as the compilable version for all known buildable modules in the given directory hierarchy. restores the default version string for all modules if nil.

Parameters

Return

Parameters:

  • base_dir_path (String)

    for search of module files

  • version_string (String) (defaults to: nil)

    in <major>.<minor>.<build> format or nil to restore original version

Returns:

  • (TrueClass)

    always true



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/right_develop/utility/versioning.rb', line 80

def set_version_for_modules(base_dir_path, version_string = nil)
  restore_original_version = version_string.nil?
  version_string = DEFAULT_WINDOWS_MODULE_VERSION if restore_original_version

  # match Windows-style version string to regular expression. Windows
  # versions require four fields (major.minor.build.revision) but we
  # accept three fields per RightScale convention and default the last
  # field to one.
  version_parse = (version_string + ".1").match(/(\d+)\.(\d+)\.(\d+)\.(\d+)/)
  raise "Invalid version string" unless version_parse

  # get individual values.
  major_version_number    = version_parse[1].to_i
  minor_version_number    = version_parse[2].to_i
  build_version_number    = version_parse[3].to_i
  revision_version_number = version_parse[4].to_i

  version_string = "#{major_version_number}.#{minor_version_number}.#{build_version_number}.#{revision_version_number}"

  # generate copyright string for current year or default copyright
  # years to soothe source control.
  copyright_year = restore_original_version ? DEFAULT_COPYRIGHT_YEARS : "2010-#{Time.now.year}"
  copyright_string = "Copyright (c) #{copyright_year} RightScale Inc"

  # find and replace version string in any kind of source file used by
  # C# modules that might contain version or copyright info.
  ::Dir.chdir(base_dir_path) do
    # C# assembly info.
    ::Dir.glob(File.join('**', 'AssemblyInfo.c*')).each do |file_path|
      replacements = {
        /\[assembly\: *AssemblyVersion\(\"\d+\.\d+\.\d+\.\d+\"\)\]/ => "[assembly: AssemblyVersion(\"#{version_string}\")]",
        /\[assembly\: *AssemblyFileVersion\(\"\d+\.\d+\.\d+\.\d+\"\)\]/ => "[assembly: AssemblyFileVersion(\"#{version_string}\")]",
        /\[assembly\: *AssemblyCopyright\(\".*"\)\]/ => "[assembly: AssemblyCopyright(\"#{copyright_string}\")]",
        /\[assembly\: *AssemblyCopyrightAttribute\(\".*"\)\]/ => "[assembly: AssemblyCopyrightAttribute(\"#{copyright_string}\")]"
      }
      replace_in_file(file_path, replacements)
    end

    # C# manifests.
    ::Dir.glob(File.join('**', '*.manifest')).each do |file_path|
      replacements = {/\<assemblyIdentity +version=\"\d+\.\d+\.\d+\.\d+\"/ => "<assemblyIdentity version=\"#{version_string}\""}
      replace_in_file(file_path, replacements)
    end

    # C++ resource files.
    ::Dir.glob(File.join('**', '*.rc')).each do |file_path|
      replacements = {
        /FILEVERSION +\d+, *\d+, *\d+, *\d+/ => "FILEVERSION #{major_version_number}, #{minor_version_number}, #{build_version_number}, #{revision_version_number}",
        /PRODUCTVERSION +\d+, *\d+, *\d+, *\d+/ => "PRODUCTVERSION #{major_version_number}, #{minor_version_number}, #{build_version_number}, #{revision_version_number}",
        /VALUE +"FileVersion", *\"\d+, *\d+, *\d+, *\d+\"/ => "VALUE \"FileVersion\", \"#{version_string}\"",
        /VALUE +"FileVersion", *\"\d+\.\d+\.\d+\.\d+\"/ => "VALUE \"FileVersion\", \"#{version_string}\"",
        /VALUE +"ProductVersion", *\"\d+, *\d+, *\d+, *\d+\"/ => "VALUE \"ProductVersion\", \"#{version_string}\"",
        /VALUE +"ProductVersion", *\"\d+\.\d+\.\d+\.\d+\"/ => "VALUE \"ProductVersion\", \"#{version_string}\"",
        /VALUE +"LegalCopyright", *\".*\"/ => "VALUE \"LegalCopyright\", \"#{copyright_string}\""
      }
      replace_in_file(file_path, replacements)
    end

    # wix installer project main source.
    ::Dir.glob(File.join('**', 'Product.wxs')).each do |file_path|
      # the Windows Installer only cares about the first three elements of the version
      installerized_version = "#{major_version_number}.#{minor_version_number}.#{build_version_number}"
      replacements = {/\<\?define ProductVersion=\"\d+\.\d+\.\d+\"/ => "<?define ProductVersion=\"#{installerized_version}\""}
      replace_in_file(file_path, replacements)

      # when producing a new installer, a new product code is required
      new_guid = restore_original_version ? "{00000000-0000-0000-0000-000000000000}" : generate_guid
      replacements = {/\<\?define ProductCode=\"\{.*\}\"/ => "<?define ProductCode=\"#{new_guid}\""}
      replace_in_file(file_path, replacements)
    end
  end
  true
end