codders-curb 0.8.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.
Files changed (45) hide show
  1. data/LICENSE +51 -0
  2. data/README +194 -0
  3. data/Rakefile +320 -0
  4. data/doc.rb +42 -0
  5. data/ext/curb.c +977 -0
  6. data/ext/curb.h +52 -0
  7. data/ext/curb_easy.c +3404 -0
  8. data/ext/curb_easy.h +90 -0
  9. data/ext/curb_errors.c +647 -0
  10. data/ext/curb_errors.h +129 -0
  11. data/ext/curb_macros.h +159 -0
  12. data/ext/curb_multi.c +633 -0
  13. data/ext/curb_multi.h +26 -0
  14. data/ext/curb_postfield.c +523 -0
  15. data/ext/curb_postfield.h +40 -0
  16. data/ext/curb_upload.c +80 -0
  17. data/ext/curb_upload.h +30 -0
  18. data/ext/extconf.rb +399 -0
  19. data/lib/curb.rb +4 -0
  20. data/lib/curl.rb +57 -0
  21. data/lib/curl/easy.rb +468 -0
  22. data/lib/curl/multi.rb +248 -0
  23. data/tests/alltests.rb +3 -0
  24. data/tests/bug_crash_on_debug.rb +39 -0
  25. data/tests/bug_crash_on_progress.rb +33 -0
  26. data/tests/bug_curb_easy_blocks_ruby_threads.rb +52 -0
  27. data/tests/bug_curb_easy_post_with_string_no_content_length_header.rb +83 -0
  28. data/tests/bug_instance_post_differs_from_class_post.rb +53 -0
  29. data/tests/bug_multi_segfault.rb +14 -0
  30. data/tests/bug_postfields_crash.rb +26 -0
  31. data/tests/bug_postfields_crash2.rb +57 -0
  32. data/tests/bug_require_last_or_segfault.rb +40 -0
  33. data/tests/bugtests.rb +9 -0
  34. data/tests/helper.rb +199 -0
  35. data/tests/mem_check.rb +65 -0
  36. data/tests/require_last_or_segfault_script.rb +36 -0
  37. data/tests/tc_curl_download.rb +75 -0
  38. data/tests/tc_curl_easy.rb +1011 -0
  39. data/tests/tc_curl_easy_setopt.rb +31 -0
  40. data/tests/tc_curl_multi.rb +485 -0
  41. data/tests/tc_curl_postfield.rb +143 -0
  42. data/tests/timeout.rb +100 -0
  43. data/tests/timeout_server.rb +33 -0
  44. data/tests/unittests.rb +2 -0
  45. metadata +133 -0
data/LICENSE ADDED
@@ -0,0 +1,51 @@
1
+ Copyright (c) 2006 Ross Bamford (rosco AT roscopeco DOT co DOT uk).
2
+ Curb is free software licensed under the following terms:
3
+
4
+ 1. You may make and give away verbatim copies of the source form of the
5
+ software without restriction, provided that you duplicate all of the
6
+ original copyright notices and associated disclaimers.
7
+
8
+ 2. You may modify your copy of the software in any way, provided that
9
+ you do at least ONE of the following:
10
+
11
+ a) place your modifications in the Public Domain or otherwise
12
+ make them Freely Available, such as by posting said
13
+ modifications to Usenet or an equivalent medium, or by allowing
14
+ the author to include your modifications in the software.
15
+
16
+ b) use the modified software only within your corporation or
17
+ organization.
18
+
19
+ c) give non-standard binaries non-standard names, with
20
+ instructions on where to get the original software distribution.
21
+
22
+ d) make other distribution arrangements with the author.
23
+
24
+ 3. You may distribute the software in object code or binary form,
25
+ provided that you do at least ONE of the following:
26
+
27
+ a) distribute the binaries and library files of the software,
28
+ together with instructions (in the manual page or equivalent)
29
+ on where to get the original distribution.
30
+
31
+ b) accompany the distribution with the machine-readable source of
32
+ the software.
33
+
34
+ c) give non-standard binaries non-standard names, with
35
+ instructions on where to get the original software distribution.
36
+
37
+ d) make other distribution arrangements with the author.
38
+
39
+ 4. You may modify and include the part of the software into any other
40
+ software (possibly commercial).
41
+
42
+ 5. The scripts and library files supplied as input to or produced as
43
+ output from the software do not automatically fall under the
44
+ copyright of the software, but belong to whomever generated them,
45
+ and may be sold commercially, and may be aggregated with this
46
+ software.
47
+
48
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
49
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
50
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
51
+ PURPOSE.
data/README ADDED
@@ -0,0 +1,194 @@
1
+ # Curb - Libcurl bindings for Ruby
2
+
3
+ + [rubyforge rdoc](http://curb.rubyforge.org/)
4
+ + [rubyforge project](http://rubyforge.org/projects/curb)
5
+ + [github project](http://github.com/taf2/curb/tree/master)
6
+
7
+ Curb (probably CUrl-RuBy or something) provides Ruby-language bindings for the
8
+ libcurl(3), a fully-featured client-side URL transfer library.
9
+ cURL and libcurl live at [http://curl.haxx.se/](http://curl.haxx.se/) .
10
+
11
+ Curb is a work-in-progress, and currently only supports libcurl's 'easy' and 'multi' modes.
12
+
13
+ ## License
14
+
15
+ Curb is copyright (c)2006 Ross Bamford, and released under the terms of the
16
+ Ruby license. See the LICENSE file for the gory details.
17
+
18
+ ## You will need
19
+
20
+ + A working Ruby installation (1.8+, tested with 1.8.6, 1.8.7, 1.9.1, and 1.9.2)
21
+ + A working (lib)curl installation, with development stuff (7.5+, tested with 7.19.x)
22
+ + A sane build environment (e.g. gcc, make)
23
+
24
+ ## Installation...
25
+
26
+ ... will usually be as simple as:
27
+
28
+ $ gem install curb
29
+
30
+ Or, if you downloaded the archive:
31
+
32
+ $ rake install
33
+
34
+ If you have a wierd setup, you might need extconf options. In this case, pass
35
+ them like so:
36
+
37
+ $ rake install EXTCONF_OPTS='--with-curl-dir=/path/to/libcurl --prefix=/what/ever'
38
+
39
+ Curb is tested only on GNU/Linux x86 and Mac OSX - YMMV on other platforms.
40
+ If you do use another platform and experience problems, or if you can
41
+ expand on the above instructions, please report the issue at http://github.com/taf2/curb/issues
42
+
43
+ On Ubuntu, the dependencies can be satisfied by installing the following packages:
44
+
45
+ $ sudo apt-get install libcurl3 libcurl3-gnutls libcurl4-openssl-dev
46
+
47
+ Curb has fairly extensive RDoc comments in the source. You can build the
48
+ documentation with:
49
+
50
+ $ rake doc
51
+
52
+ ## Usage & examples
53
+
54
+ Curb provides two classes:
55
+
56
+ + Curl::Easy - simple API, for day-to-day tasks.
57
+ + Curl::Multi - more advanced API, for operating on multiple URLs simultaneously.
58
+
59
+ ### Super simple API (less typing)
60
+
61
+ http = Curl.get("http://www.google.com/")
62
+ puts http.body_str
63
+
64
+ http = Curl.post("http://www.google.com/", {:foo => "bar"})
65
+ puts http.body_str
66
+
67
+ http = Curl.get("http://www.google.com/") do|http|
68
+ http.headers['Cookie'] = 'foo=1;bar=2'
69
+ end
70
+ puts http.body_str
71
+
72
+ ### Simple fetch via HTTP:
73
+
74
+ c = Curl::Easy.perform("http://www.google.co.uk")
75
+ puts c.body_str
76
+
77
+ Same thing, more manual:
78
+
79
+ c = Curl::Easy.new("http://www.google.co.uk")
80
+ c.perform
81
+ puts c.body_str
82
+
83
+ ### Additional config:
84
+
85
+ Curl::Easy.perform("http://www.google.co.uk") do |curl|
86
+ curl.headers["User-Agent"] = "myapp-0.0"
87
+ curl.verbose = true
88
+ end
89
+
90
+ Same thing, more manual:
91
+
92
+ c = Curl::Easy.new("http://www.google.co.uk") do |curl|
93
+ curl.headers["User-Agent"] = "myapp-0.0"
94
+ curl.verbose = true
95
+ end
96
+
97
+ c.perform
98
+
99
+ ### HTTP basic authentication:
100
+
101
+ c = Curl::Easy.new("http://github.com/")
102
+ c.http_auth_types = :basic
103
+ c.username = 'foo'
104
+ c.password = 'bar'
105
+ c.perform
106
+
107
+ ### Supplying custom handlers:
108
+
109
+ c = Curl::Easy.new("http://www.google.co.uk")
110
+
111
+ c.on_body { |data| print(data) }
112
+ c.on_header { |data| print(data) }
113
+
114
+ c.perform
115
+
116
+ ### Reusing Curls:
117
+
118
+ c = Curl::Easy.new
119
+
120
+ ["http://www.google.co.uk", "http://www.ruby-lang.org/"].map do |url|
121
+ c.url = url
122
+ c.perform
123
+ c.body_str
124
+ end
125
+
126
+ ### HTTP POST form:
127
+
128
+ c = Curl::Easy.http_post("http://my.rails.box/thing/create",
129
+ Curl::PostField.content('thing[name]', 'box'),
130
+ Curl::PostField.content('thing[type]', 'storage'))
131
+
132
+ ### HTTP POST file upload:
133
+
134
+ c = Curl::Easy.new("http://my.rails.box/files/upload")
135
+ c.multipart_form_post = true
136
+ c.http_post(Curl::PostField.file('thing[file]', 'myfile.rb'))
137
+
138
+ ### Multi Interface (Basic HTTP GET):
139
+
140
+ # make multiple GET requests
141
+ easy_options = {:follow_location => true}
142
+ multi_options = {:pipeline => true}
143
+
144
+ Curl::Multi.get('url1','url2','url3','url4','url5', easy_options, multi_options) do|easy|
145
+ # do something interesting with the easy response
146
+ puts easy.last_effective_url
147
+ end
148
+
149
+ ### Multi Interface (Basic HTTP POST):
150
+
151
+ # make multiple POST requests
152
+ easy_options = {:follow_location => true, :multipart_form_post => true}
153
+ multi_options = {:pipeline => true}
154
+
155
+ url_fields = [
156
+ { :url => 'url1', :post_fields => {'f1' => 'v1'} },
157
+ { :url => 'url2', :post_fields => {'f1' => 'v1'} },
158
+ { :url => 'url3', :post_fields => {'f1' => 'v1'} }
159
+ ]
160
+
161
+ Curl::Multi.post(url_fields, easy_options, multi_options) do|easy|
162
+ # do something interesting with the easy response
163
+ puts easy.last_effective_url
164
+ end
165
+
166
+ ### Multi Interface (Advanced):
167
+
168
+ responses = {}
169
+ requests = ["http://www.google.co.uk/", "http://www.ruby-lang.org/"]
170
+ m = Curl::Multi.new
171
+ # add a few easy handles
172
+ requests.each do |url|
173
+ responses[url] = ""
174
+ c = Curl::Easy.new(url) do|curl|
175
+ curl.follow_location = true
176
+ curl.on_body{|data| responses[url] << data; data.size }
177
+ curl.on_success {|easy| puts "success, add more easy handles" }
178
+ end
179
+ m.add(c)
180
+ end
181
+
182
+ m.perform do
183
+ puts "idling... can do some work here"
184
+ end
185
+
186
+ requests.each do|url|
187
+ puts responses[url]
188
+ end
189
+
190
+ ### Easy Callbacks
191
+
192
+ on_success: is called when the response code is 20x
193
+ on_failure: is called when the response code is not success, including redirects e.g. 30x
194
+ on_complete: is called in all cases.
data/Rakefile ADDED
@@ -0,0 +1,320 @@
1
+ # $Id$
2
+ #
3
+ require 'rake/clean'
4
+ require 'rake/testtask'
5
+ begin
6
+ require 'rdoc/task'
7
+ rescue LoadError => e
8
+ require 'rake/rdoctask'
9
+ end
10
+
11
+ CLEAN.include '**/*.o'
12
+ CLEAN.include "**/*.#{(defined?(RbConfig) ? RbConfig : Config)::MAKEFILE_CONFIG['DLEXT']}"
13
+ CLOBBER.include 'doc'
14
+ CLOBBER.include '**/*.log'
15
+ CLOBBER.include '**/Makefile'
16
+ CLOBBER.include '**/extconf.h'
17
+
18
+ def announce(msg='')
19
+ $stderr.puts msg
20
+ end
21
+
22
+ desc "Default Task (Test project)"
23
+ task :default => :test
24
+
25
+ # Determine the current version of the software
26
+ if File.read('ext/curb.h') =~ /\s*CURB_VERSION\s*['"](\d.+)['"]/
27
+ CURRENT_VERSION = $1
28
+ else
29
+ CURRENT_VERSION = "0.0.0"
30
+ end
31
+
32
+ if ENV['REL']
33
+ PKG_VERSION = ENV['REL']
34
+ else
35
+ PKG_VERSION = CURRENT_VERSION
36
+ end
37
+
38
+ task :test_ver do
39
+ puts PKG_VERSION
40
+ end
41
+
42
+ # Make tasks -----------------------------------------------------
43
+ make_program = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make'
44
+ MAKECMD = ENV['MAKE_CMD'] || make_program
45
+ MAKEOPTS = ENV['MAKE_OPTS'] || ''
46
+
47
+ CURB_SO = "ext/curb_core.#{(defined?(RbConfig) ? RbConfig : Config)::MAKEFILE_CONFIG['DLEXT']}"
48
+
49
+ file 'ext/Makefile' => 'ext/extconf.rb' do
50
+ Dir.chdir('ext') do
51
+ ruby "extconf.rb #{ENV['EXTCONF_OPTS']}"
52
+ end
53
+ end
54
+
55
+ def make(target = '')
56
+ Dir.chdir('ext') do
57
+ pid = system("#{MAKECMD} #{MAKEOPTS} #{target}")
58
+ $?.exitstatus
59
+ end
60
+ end
61
+
62
+ # Let make handle dependencies between c/o/so - we'll just run it.
63
+ file CURB_SO => (['ext/Makefile'] + Dir['ext/*.c'] + Dir['ext/*.h']) do
64
+ m = make
65
+ fail "Make failed (status #{m})" unless m == 0
66
+ end
67
+
68
+ desc "Compile the shared object"
69
+ task :compile => [CURB_SO]
70
+
71
+ desc "Create the markdown file"
72
+ task :markdown do
73
+ cp "README", "README.markdown"
74
+ end
75
+
76
+ desc "Install to your site_ruby directory"
77
+ task :install => :alltests do
78
+ m = make 'install'
79
+ fail "Make install failed (status #{m})" unless m == 0
80
+ end
81
+
82
+ # Test Tasks ---------------------------------------------------------
83
+ task :ta => :alltests
84
+ task :tu => :unittests
85
+ task :test => [:rmpid,:unittests]
86
+
87
+ task :rmpid do
88
+ FileUtils.rm_rf Dir.glob("tests/server_lock-*")
89
+ end
90
+
91
+ if ENV['RELTEST']
92
+ announce "Release task testing - not running regression tests on alltests"
93
+ task :alltests => [:unittests]
94
+ else
95
+ task :alltests => [:unittests, :bugtests]
96
+ end
97
+
98
+ Rake::TestTask.new(:unittests) do |t|
99
+ t.test_files = FileList['tests/tc_*.rb']
100
+ t.verbose = false
101
+ end
102
+
103
+ Rake::TestTask.new(:bugtests) do |t|
104
+ t.test_files = FileList['tests/bug_*.rb']
105
+ t.verbose = false
106
+ end
107
+
108
+ #Rake::TestTask.new(:funtests) do |t|
109
+ # t.test_files = FileList['test/func_*.rb']
110
+ #t.warning = true
111
+ #t.warning = true
112
+ #end
113
+
114
+ task :unittests => :compile
115
+ task :bugtests => :compile
116
+
117
+ def has_gem?(file,name)
118
+ begin
119
+ require file
120
+ has_http_persistent = true
121
+ rescue LoadError => e
122
+ puts "Skipping #{name}"
123
+ end
124
+ end
125
+
126
+ desc "Benchmark curl against http://127.0.0.1/zeros-2k - will fail if /zeros-2k or 127.0.0.1 are missing"
127
+ task :bench do
128
+ sh "ruby bench/curb_easy.rb"
129
+ sh "ruby bench/curb_multi.rb"
130
+ sh "ruby bench/nethttp_test.rb" if has_gem?("net/http/persistent","net-http-persistent")
131
+ sh "ruby bench/patron_test.rb" if has_gem?("patron","patron")
132
+ sh "ruby bench/typhoeus_test.rb" if has_gem?("typhoeus","typhoeus")
133
+ sh "ruby bench/typhoeus_hydra_test.rb" if has_gem?("typhoeus","typhoeus")
134
+ end
135
+
136
+ # RDoc Tasks ---------------------------------------------------------
137
+ desc "Create the RDOC documentation"
138
+ task :doc do
139
+ ruby "doc.rb #{ENV['DOC_OPTS']}"
140
+ end
141
+
142
+ desc "Publish the RDoc documentation to project web site"
143
+ task :doc_upload => [ :doc ] do
144
+ if ENV['RELTEST']
145
+ announce "Release Task Testing, skipping doc upload"
146
+ else
147
+ unless ENV['RUBYFORGE_ACCT']
148
+ raise "Need to set RUBYFORGE_ACCT to your rubyforge.org user name (e.g. 'fred')"
149
+ end
150
+
151
+ require 'rake/contrib/sshpublisher'
152
+ Rake::SshDirPublisher.new(
153
+ "#{ENV['RUBYFORGE_ACCT']}@rubyforge.org",
154
+ "/var/www/gforge-projects/curb",
155
+ "doc"
156
+ ).upload
157
+ end
158
+ end
159
+
160
+ if ! defined?(Gem)
161
+ warn "Package Target requires RubyGEMs"
162
+ else
163
+ desc 'Generate gem specification'
164
+ task :gemspec do
165
+ require 'erb'
166
+ tspec = ERB.new(File.read(File.join(File.dirname(__FILE__),'lib','curb.gemspec.erb')))
167
+ File.open(File.join(File.dirname(__FILE__),'curb.gemspec'),'wb') do|f|
168
+ f << tspec.result
169
+ end
170
+ end
171
+
172
+ desc 'Build gem'
173
+ task :package => :gemspec do
174
+ require 'rubygems/specification'
175
+ spec_source = File.read File.join(File.dirname(__FILE__),'curb.gemspec')
176
+ spec = nil
177
+ # see: http://gist.github.com/16215
178
+ Thread.new { spec = eval("$SAFE = 3\n#{spec_source}") }.join
179
+ spec.validate
180
+ Gem::Builder.new(spec).build
181
+ end
182
+
183
+ task :static do
184
+ ENV['STATIC_BUILD'] = '1'
185
+ end
186
+
187
+ task :binary_gemspec => [:static, :compile] do
188
+ require 'erb'
189
+ ENV['BINARY_PACKAGE'] = '1'
190
+ tspec = ERB.new(File.read(File.join(File.dirname(__FILE__),'lib','curb.gemspec.erb')))
191
+
192
+ File.open(File.join(File.dirname(__FILE__),'curb-binary.gemspec'),'wb') do|f|
193
+ f << tspec.result
194
+ end
195
+ end
196
+
197
+ desc 'Strip extra strings from Binary'
198
+ task :binary_strip do
199
+ strip = '/usr/bin/strip'
200
+ if File.exist?(strip) and `#{strip} -h 2>&1`.match(/GNU/)
201
+ sh "#{strip} #{CURB_SO}"
202
+ end
203
+ end
204
+
205
+ desc 'Build gem'
206
+ task :binary_package => [:binary_gemspec, :binary_strip] do
207
+ require 'rubygems/specification'
208
+ spec_source = File.read File.join(File.dirname(__FILE__),'curb-binary.gemspec')
209
+ spec = nil
210
+ # see: http://gist.github.com/16215
211
+ Thread.new { spec = eval("$SAFE = 3\n#{spec_source}") }.join
212
+ spec.validate
213
+ Gem::Builder.new(spec).build
214
+ end
215
+ end
216
+
217
+ # --------------------------------------------------------------------
218
+ # Creating a release
219
+ desc "Make a new release (Requires SVN commit / webspace access)"
220
+ task :release => [
221
+ :prerelease,
222
+ :clobber,
223
+ :alltests,
224
+ :update_version,
225
+ :package,
226
+ :tag,
227
+ :doc_upload] do
228
+
229
+ announce
230
+ announce "**************************************************************"
231
+ announce "* Release #{PKG_VERSION} Complete."
232
+ announce "* Packages ready to upload."
233
+ announce "**************************************************************"
234
+ announce
235
+ end
236
+
237
+ # Validate that everything is ready to go for a release.
238
+ task :prerelease do
239
+ announce
240
+ announce "**************************************************************"
241
+ announce "* Making RubyGem Release #{PKG_VERSION}"
242
+ announce "* (current version #{CURRENT_VERSION})"
243
+ announce "**************************************************************"
244
+ announce
245
+
246
+ # Is a release number supplied?
247
+ unless ENV['REL']
248
+ fail "Usage: rake release REL=x.y.z [REUSE=tag_suffix]"
249
+ end
250
+
251
+ # Is the release different than the current release.
252
+ # (or is REUSE set?)
253
+ if PKG_VERSION == CURRENT_VERSION && ! ENV['REUSE']
254
+ fail "Current version is #{PKG_VERSION}, must specify REUSE=tag_suffix to reuse version"
255
+ end
256
+
257
+ # Are all source files checked in?
258
+ if ENV['RELTEST']
259
+ announce "Release Task Testing, skipping checked-in file test"
260
+ else
261
+ announce "Checking for unchecked-in files..."
262
+ data = `svn status`
263
+ unless data =~ /^$/
264
+ fail "SVN status is not clean ... do you have unchecked-in files?"
265
+ end
266
+ announce "No outstanding checkins found ... OK"
267
+ end
268
+
269
+ announce "Doc will try to use GNU cpp if available"
270
+ ENV['DOC_OPTS'] = "--cpp"
271
+ end
272
+
273
+ # Used during release packaging if a REL is supplied
274
+ task :update_version do
275
+ unless PKG_VERSION == CURRENT_VERSION
276
+ pkg_vernum = PKG_VERSION.tr('.','').sub(/^0*/,'')
277
+ pkg_vernum << '0' until pkg_vernum.length > 2
278
+
279
+ File.open('ext/curb.h.new','w+') do |f|
280
+ maj, min, mic, patch = /(\d+)\.(\d+)(?:\.(\d+))?(?:\.(\d+))?/.match(PKG_VERSION).captures
281
+ f << File.read('ext/curb.h').
282
+ gsub(/CURB_VERSION\s+"(\d.+)"/) { "CURB_VERSION \"#{PKG_VERSION}\"" }.
283
+ gsub(/CURB_VER_NUM\s+\d+/) { "CURB_VER_NUM #{pkg_vernum}" }.
284
+ gsub(/CURB_VER_MAJ\s+\d+/) { "CURB_VER_MAJ #{maj}" }.
285
+ gsub(/CURB_VER_MIN\s+\d+/) { "CURB_VER_MIN #{min}" }.
286
+ gsub(/CURB_VER_MIC\s+\d+/) { "CURB_VER_MIC #{mic || 0}" }.
287
+ gsub(/CURB_VER_PATCH\s+\d+/) { "CURB_VER_PATCH #{patch || 0}" }
288
+ end
289
+ mv('ext/curb.h.new', 'ext/curb.h')
290
+ if ENV['RELTEST']
291
+ announce "Release Task Testing, skipping commiting of new version"
292
+ else
293
+ sh %{svn commit -m "Updated to version #{PKG_VERSION}" ext/curb.h}
294
+ end
295
+ end
296
+ end
297
+
298
+ # "Create a new SVN tag with the latest release number (REL=x.y.z)"
299
+ task :tag => [:prerelease] do
300
+ reltag = "curb-#{PKG_VERSION}"
301
+ reltag << ENV['REUSE'] if ENV['REUSE']
302
+ announce "Tagging SVN with [#{reltag}]"
303
+ if ENV['RELTEST']
304
+ announce "Release Task Testing, skipping SVN tagging"
305
+ else
306
+ # need to get current base URL
307
+ s = `svn info`
308
+ if s =~ /URL:\s*([^\n]*)\n/
309
+ svnroot = $1
310
+ if svnroot =~ /^(.*)\/trunk/i
311
+ svnbase = $1
312
+ sh %{svn cp #{svnroot} #{svnbase}/TAGS/#{reltag} -m "Release #{PKG_VERSION}"}
313
+ else
314
+ fail "Please merge to trunk before making a release"
315
+ end
316
+ else
317
+ fail "Unable to determine repository URL from 'svn info' - is this a working copy?"
318
+ end
319
+ end
320
+ end