asrake 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,55 @@
1
+ require 'rake/tasklib'
2
+ require 'zip/zip'
3
+
4
+ module ASRake
5
+ class PackageTask < Rake::TaskLib
6
+
7
+ attr_accessor :output
8
+ attr_accessor :files
9
+
10
+ attr_reader :output_file
11
+ attr_reader :output_dir
12
+
13
+ def initialize(name = :package)
14
+
15
+ yield self if block_given?
16
+
17
+ fail "You must define 'output' for #{self}" if output == nil
18
+ fail "You must define 'files' to include for #{self}" if files == nil
19
+
20
+ #define named task first so if desc was called it will be attached to it instead of the file task
21
+ Rake::Task.define_task name do
22
+ puts "#{c output} (#{File.size(output)} bytes)"
23
+ end
24
+
25
+ #if the task name is a hash (ie, has dependencies defined) make sure we pull out the task name from it
26
+ name, _ = name.first if name.is_a? Hash
27
+
28
+ @output_dir = File.dirname(output)
29
+ @output_file = File.basename(output)
30
+
31
+ directory output_dir
32
+
33
+ # setup file dependencies
34
+ file output => output_dir
35
+ files.each do |to, from|
36
+ file output => [cf(from)]
37
+ end
38
+
39
+ #add output file task as a dependency to the named task created
40
+ task name => output
41
+
42
+ #create the zip task
43
+ file output do
44
+ rm_r output rescue nil
45
+ Zip::ZipFile.open(output, Zip::ZipFile::CREATE) do |zipfile|
46
+ files.each do |to, from|
47
+ zipfile.add(cf(to), cf(from))
48
+ end
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,90 @@
1
+ # (The MIT License)
2
+ #
3
+ # Copyright (c) 2010-2010 Stephen Touset
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ class Version::Component
25
+ attr_accessor :digits
26
+ attr_accessor :letter
27
+
28
+ #
29
+ # Creates a single Component of a version, consisting of digits and
30
+ # possibly a letter. For example, +1+, +3a+, +12+, or +0+.
31
+ #
32
+ def initialize(component)
33
+ parts = component.split /(?=\D)/
34
+
35
+ self.digits = parts[0].to_i
36
+ self.letter = parts[1].to_s.strip
37
+ end
38
+
39
+ def initialize_copy(other)
40
+ self.digits = other.digits
41
+ self.letter = other.letter.dup
42
+ end
43
+
44
+ def prerelease?
45
+ not self.letter.empty?
46
+ end
47
+
48
+ def unprerelease!
49
+ self.next! if self.prerelease?
50
+ end
51
+
52
+ def next(pre = false)
53
+ self.dup.next!(pre)
54
+ end
55
+
56
+ def next!(pre = false)
57
+ case
58
+ when ( pre and self.prerelease?) then self.letter.next!
59
+ when ( pre and not self.prerelease?) then self.letter = 'a'
60
+ when (not pre and self.prerelease?) then self.letter = ''
61
+ when (not pre and not self.prerelease?) then self.digits = self.digits.next
62
+ end
63
+
64
+ self
65
+ end
66
+
67
+ def <=>(other)
68
+ self.to_sortable_a <=> other.to_sortable_a
69
+ end
70
+
71
+ def to_sortable_a
72
+ [ self.digits, self.prerelease? ? 0 : 1, self.letter ]
73
+ end
74
+
75
+ def to_a
76
+ [ self.digits, self.letter ]
77
+ end
78
+
79
+ def to_i
80
+ self.digits
81
+ end
82
+
83
+ def to_s
84
+ self.to_a.join
85
+ end
86
+
87
+ def inspect
88
+ self.to_s.inspect
89
+ end
90
+ end
@@ -0,0 +1,250 @@
1
+ # (The MIT License)
2
+ #
3
+ # Copyright (c) 2010-2010 Stephen Touset
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ require 'pathname'
25
+
26
+ #
27
+ # Encodes version-numbering logic into a convenient class.
28
+ #
29
+ class Version
30
+ include Comparable
31
+ autoload :Component, 'asrake/version/component'
32
+ #
33
+ # Searches through the parent directories of the calling method and looks
34
+ # for a VERSION or VERSION.yml file to parse out the current version. Pass
35
+ #
36
+ # Pass a filename to +path+ to override autodetection, or pass a directory
37
+ # name as +path+ to autodetect within a given directory
38
+ #
39
+ def self.current(path = nil)
40
+ # if path is nil, detect automatically; if path is a directory, detect
41
+ # automatically in the directory; if path is a filename, use it directly
42
+ path = path ? Pathname.new(path) : self.version_file(caller.first)
43
+ path = self.version_file(path) unless path.nil? or path.file?
44
+
45
+ return nil unless path
46
+
47
+ case path.extname
48
+ when '' then Version.to_version(path.read.strip)
49
+ when '.yml' then Version.to_version(YAML::load(path.read))
50
+ end
51
+ end
52
+
53
+ #
54
+ # Attempts to detect the version file for the passed +filename+. Looks up
55
+ # the directory hierarchy for a file named VERSION or VERSION.yml. Returns
56
+ # a Pathname for the file if found, otherwise nil.
57
+ #
58
+ def self.version_file(filename)
59
+ Pathname(filename).dirname.expand_path.ascend do |d|
60
+ break d.join('VERSION') if d.join('VERSION').file?
61
+ break d.join('VERSION.yml') if d.join('VERSION.yml').file?
62
+ end
63
+ end
64
+
65
+ #
66
+ # Converts a String, Hash, or Array into a Version instance
67
+ #
68
+ def self.to_version(obj)
69
+ if obj.kind_of? String
70
+ Version.new *obj.split(%r{\.})
71
+ elsif obj.kind_of? Hash
72
+ Version.new *obj.values_at(:major, :minor, :revision, :rest)
73
+ elsif obj.kind_of? Array
74
+ Version.new *obj
75
+ end
76
+ end
77
+
78
+ #
79
+ # Creates a new version number, with a +major+ version number, +minor+
80
+ # revision number, +revision+ number, and optionally more (unnamed)
81
+ # version components.
82
+ #
83
+ def initialize(major, minor = 0, revision = nil, *rest)
84
+ self.components = [ major, minor, revision, *rest ]
85
+ end
86
+
87
+ #
88
+ # For +major+, +minor+, and +revision+, make a helper method that gets and
89
+ # sets each based on accessing indexes.
90
+ #--
91
+ # TODO: make these rdoc-capable
92
+ #++
93
+ #
94
+ [ :major, :minor, :revision ].to_enum.each.with_index do |component, i|
95
+ define_method(:"#{component}") { self.components[i] ? self.components[i].to_s : nil }
96
+ define_method(:"#{component}=") {|v| self[i] = v }
97
+ end
98
+
99
+ #
100
+ # Set the component of the Version at +index+ to +value+. Zeroes out any
101
+ # trailing components.
102
+ #
103
+ # If +index+ is greater than the length of the version number, pads the
104
+ # version number with zeroes until +index+.
105
+ #
106
+ def []=(index, value)
107
+ return self.resize!(index) if value.nil? || value.to_s.empty?
108
+ return self[self.length + index] = value if index < 0
109
+
110
+ length = self.length - index
111
+ zeroes = Array.new length.abs, Version::Component.new('0')
112
+ value = Version::Component.new(value.to_s)
113
+
114
+ if length >= 0
115
+ self.components[index, length] = zeroes
116
+ self.components[index] = value
117
+ else
118
+ self.components += zeroes
119
+ self.components << value
120
+ end
121
+ end
122
+
123
+ def prerelease?
124
+ self.components.any? {|c| c.prerelease? }
125
+ end
126
+
127
+ #
128
+ # Resizes the Version to +length+, removing any trailing components. Is a
129
+ # no-op if +length+ is greater than its current length.
130
+ #
131
+ def resize!(length)
132
+ self.components = self.components.take(length)
133
+ self
134
+ end
135
+
136
+ #
137
+ # Bumps the version number. Pass +component+ to bump a component other than
138
+ # the least-significant part. Set +pre+ to true if you want to bump the
139
+ # component to a prerelease version. Set +trim+ to true if you want the
140
+ # version to be resized to only large enough to contain the component set.
141
+ #
142
+ # "1.0.4a".bump! # => '1.0.4'
143
+ # "1.0.4a".bump!(:pre) # => '1.0.4b'
144
+ # "1.0.4a".bump!(:minor, false, true) # => '1.1'
145
+ # "1.0.4a".bump!(:minor, true, true) # => '1.1a
146
+ # "1.0.4a".bump!(:minor, true, false) # => '1.1.0a'
147
+ #
148
+ def bump!(component = -1, pre = false, trim = false)
149
+ case component
150
+ when :major then self.bump!(0, pre, trim)
151
+ when :minor then self.bump!(1, pre, trim)
152
+ when :revision then self.bump!(2, pre, trim)
153
+ when :pre then self.bump!(-1, true, trim)
154
+ else
155
+ # resize to match the new length, if applicable
156
+ self.resize!(component + 1) if (trim or component >= self.length)
157
+
158
+ # mark all but the changed bit as non-prerelease
159
+ self[0...component].each(&:unprerelease!)
160
+
161
+ # I don't even understand this part any more; god help you
162
+ self[component] = self[component].next if pre and self.prerelease? and component == self.length - 1
163
+ self[component] = self[component].next unless pre and self.prerelease? and component == -1
164
+ self[-1] = self[-1].next(true) if pre
165
+ self
166
+ end
167
+ end
168
+
169
+ def bump(component = -1, pre = false, trim = false)
170
+ return (Version.to_version(self.to_hash)).bump!(component, pre, trim)
171
+ end
172
+
173
+ #
174
+ # Returns the current length of the version number.
175
+ #
176
+ def length
177
+ self.components.length
178
+ end
179
+
180
+ #
181
+ # Compares a Version against any +other+ object that responds to
182
+ # +to_version+.
183
+ #
184
+ def <=>(other)
185
+ self.components <=> other.to_version.components
186
+ end
187
+
188
+ #
189
+ # Converts the version number into an array of its components.
190
+ #
191
+ def to_a
192
+ self.components.map {|c| c.to_s }
193
+ end
194
+
195
+ #
196
+ # Converts the version number into a hash of its components.
197
+ #
198
+ def to_hash
199
+ { :major => self.major,
200
+ :minor => self.minor,
201
+ :revision => self.revision,
202
+ :rest => self.length > 3 ? self.to_a.drop(3) : nil }.
203
+ delete_if {|k,v| v.nil? }
204
+ end
205
+
206
+ #
207
+ # The canonical representation of a version number.
208
+ #
209
+ def to_s
210
+ self.to_a.join('.')
211
+ end
212
+
213
+ #
214
+ # Returns +self+.
215
+ #
216
+ def to_version
217
+ self
218
+ end
219
+
220
+ #
221
+ # Returns a YAML representation of the version number.
222
+ #
223
+ def to_yaml
224
+ YAML::dump(self.to_hash)
225
+ end
226
+
227
+ #
228
+ # Returns a human-friendly version format.
229
+ #
230
+ def inspect
231
+ self.to_s.inspect
232
+ end
233
+
234
+ protected
235
+
236
+ #
237
+ # Retrieves the component of the Version at +index+.
238
+ #
239
+ def [](index)
240
+ self.components[index] || Component.new('0')
241
+ end
242
+
243
+ def components
244
+ @components ||= []
245
+ end
246
+
247
+ def components=(components)
248
+ components.each_with_index {|c, i| self[i] = c }
249
+ end
250
+ end
@@ -0,0 +1,90 @@
1
+ require 'rake/tasklib'
2
+
3
+ require 'asrake/version/version'
4
+
5
+ module ASRake
6
+ class VersionTask < Rake::TaskLib
7
+
8
+ attr_accessor :filename
9
+ attr_accessor :filetype
10
+ attr_reader :version
11
+
12
+ def initialize(name = :version, filename = "VERSION")
13
+ self.filename = filename
14
+
15
+ yield self if block_given?
16
+
17
+ # fail if no filename was provided
18
+ fail "You must define 'filename' for #{self}" if filename == nil
19
+
20
+ @path = Pathname.new(self.filename)
21
+ # set filetype from the filename if it hasn't been set already
22
+ self.filetype ||= @path.extname[1..-1]
23
+
24
+ # read in the current version
25
+ contents = @path.read rescue '0.0.0'
26
+ @version = case filetype.to_s
27
+ when '' then Version.to_version(contents.chomp)
28
+ when 'yml' then Version.to_version(YAML::load(contents))
29
+ end
30
+
31
+ # create the primary version task
32
+ desc "Increment version from #{@version}"
33
+ @version_task = Rake::Task.define_task name
34
+
35
+ # if the task name is a hash (ie, has dependencies defined) make sure we pull out the task name from it
36
+ name, _ = name.first if name.is_a? Hash
37
+
38
+ Rake::Task.define_task name, [:part] => filename do |t, args|
39
+ case (args[:part] || "").chomp.downcase
40
+ when 'major'
41
+ puts "Incremented version from #{@version} to #{save(@version.bump!(:major))}"
42
+ when 'minor'
43
+ puts "Incremented version from #{@version} to #{save(@version.bump!(:minor))}"
44
+ when 'revision', 'rev', 'patch'
45
+ puts "Incremented version from #{@version} to #{save(@version.bump!(:revision))}"
46
+ when ''
47
+ puts "Current version is #{@version}"
48
+ else
49
+ fail "Invalid version argument '#{args[:part]}', run 'rake #{@help_task}' for help."
50
+ end
51
+ @sync_task.execute()
52
+ end
53
+
54
+ file filename do
55
+ puts "Created version #{save(Version.to_version(ENV['VERSION'] || '0.0.0'))} at #{filename}"
56
+ end
57
+
58
+ # create a namespace with the same name as the task to provide further options
59
+ namespace name do
60
+
61
+ #add to this task to perform some operation post-bump
62
+ @sync_task = task :sync
63
+
64
+ desc "Display help for version task"
65
+ @help_task = task :help do
66
+ puts "Version number format is Major.Minor.Revision (aka Major.Minor.Patch)"
67
+ puts "To display the current version, run without arguments"
68
+ puts "rake #{@version_task} => #{@version}"
69
+ puts "To increment the version, provide the respective part as an argument."
70
+ puts "rake #{@version_task}[major] => #{@version.bump(:major)}"
71
+ puts "rake #{@version_task}[minor] => #{@version.bump(:minor)}"
72
+ puts "rake #{@version_task}[revision] => #{@version.bump(:revision)}"
73
+ end
74
+ end
75
+
76
+ end
77
+
78
+ private
79
+
80
+ def save(version)
81
+ @path.open('w') do |file|
82
+ file << case filetype.to_s
83
+ when '' then version.to_s + "\n"
84
+ when 'yml' then version.to_yaml
85
+ end
86
+ end
87
+ return version
88
+ end
89
+ end
90
+ end