htauth 2.2.0 → 3.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/HISTORY.md +21 -1
  3. data/Manifest.txt +5 -27
  4. data/README.md +51 -31
  5. data/exe/htdigest-ruby +14 -0
  6. data/exe/htpasswd-ruby +14 -0
  7. data/htauth.gemspec +33 -0
  8. data/lib/htauth/algorithm.rb +42 -29
  9. data/lib/htauth/argon2.rb +86 -0
  10. data/lib/htauth/bcrypt.rb +17 -11
  11. data/lib/htauth/cli/digest.rb +42 -49
  12. data/lib/htauth/cli/passwd.rb +127 -114
  13. data/lib/htauth/cli.rb +5 -4
  14. data/lib/htauth/console.rb +9 -6
  15. data/lib/htauth/crypt.rb +11 -9
  16. data/lib/htauth/descendant_tracker.rb +11 -9
  17. data/lib/htauth/digest_entry.rb +22 -19
  18. data/lib/htauth/digest_file.rb +25 -18
  19. data/lib/htauth/entry.rb +3 -1
  20. data/lib/htauth/error.rb +6 -5
  21. data/lib/htauth/file.rb +35 -39
  22. data/lib/htauth/md5.rb +35 -34
  23. data/lib/htauth/passwd_entry.rb +29 -38
  24. data/lib/htauth/passwd_file.rb +32 -27
  25. data/lib/htauth/plaintext.rb +7 -5
  26. data/lib/htauth/sha1.rb +9 -7
  27. data/lib/htauth/version.rb +3 -1
  28. data/lib/htauth.rb +29 -28
  29. metadata +24 -113
  30. data/Rakefile +0 -27
  31. data/bin/htdigest-ruby +0 -12
  32. data/bin/htpasswd-ruby +0 -12
  33. data/spec/algorithm_spec.rb +0 -8
  34. data/spec/bcrypt_spec.rb +0 -33
  35. data/spec/cli/digest_spec.rb +0 -149
  36. data/spec/cli/passwd_spec.rb +0 -330
  37. data/spec/crypt_spec.rb +0 -12
  38. data/spec/digest_entry_spec.rb +0 -60
  39. data/spec/digest_file_spec.rb +0 -65
  40. data/spec/md5_spec.rb +0 -13
  41. data/spec/passwd_entry_spec.rb +0 -159
  42. data/spec/passwd_file_spec.rb +0 -84
  43. data/spec/plaintext_spec.rb +0 -11
  44. data/spec/sha1_spec.rb +0 -11
  45. data/spec/spec_helper.rb +0 -28
  46. data/spec/test.add.digest +0 -3
  47. data/spec/test.add.passwd +0 -3
  48. data/spec/test.delete.digest +0 -1
  49. data/spec/test.delete.passwd +0 -1
  50. data/spec/test.original.digest +0 -2
  51. data/spec/test.original.passwd +0 -2
  52. data/spec/test.update.digest +0 -2
  53. data/spec/test.update.passwd +0 -2
  54. data/tasks/default.rake +0 -242
  55. data/tasks/this.rb +0 -208
  56. /data/{LICENSE → LICENSE.txt} +0 -0
@@ -1,159 +0,0 @@
1
- require 'spec_helper'
2
- require 'htauth/passwd_entry'
3
-
4
- describe HTAuth::PasswdEntry do
5
- before(:each) do
6
- @alice = HTAuth::PasswdEntry.new("alice", "a secret", "crypt", { :salt => "mD" })
7
- @bob = HTAuth::PasswdEntry.new("bob", "b secret", "crypt", { :salt => "b8"})
8
- @salt = "lo1tk/.."
9
- end
10
-
11
- it "initializes with a user and realm" do
12
- _(@alice.user).must_equal "alice"
13
- end
14
-
15
- it "has the correct crypt password" do
16
- @alice.password = "a secret"
17
- _(@alice.digest).must_equal "mDwdZuXalQ5zk"
18
- end
19
-
20
- it "encrypts correctly for md5" do
21
- bob = HTAuth::PasswdEntry.new("bob", "b secret", "md5", { :salt => @salt })
22
- _(bob.digest).must_equal "$apr1$lo1tk/..$CarApvZPee0F6Wj1U0GxZ1"
23
- end
24
-
25
- it "encrypts correctly for sha1" do
26
- bob = HTAuth::PasswdEntry.new("bob", "b secret", "sha1", { :salt => @salt })
27
- _(bob.digest).must_equal "{SHA}b/tjGXbX80MEKVnF200S43ca4hY="
28
- end
29
-
30
- it "encrypts correctly for plaintext" do
31
- bob = HTAuth::PasswdEntry.new("bob", "b secret", "plaintext", { :salt => @salt })
32
- _(bob.digest).must_equal "b secret"
33
- end
34
-
35
- it "encrypts with crypt as a default, when parsed from crypt()'d line" do
36
- bob2 = HTAuth::PasswdEntry.from_line(@bob.to_s)
37
- _(bob2.algorithm).must_be_instance_of(HTAuth::Crypt)
38
- bob2.password = "another secret"
39
- _(bob2.algorithm).must_be_instance_of(HTAuth::Crypt)
40
- end
41
-
42
- it "encrypts with crypt as a default, when parsed from plaintext line" do
43
- p = HTAuth::PasswdEntry.new('paul', 'p secret', 'plaintext')
44
- p2 = HTAuth::PasswdEntry.from_line(p.to_s)
45
- _(p2.algorithm).must_be_instance_of(HTAuth::Plaintext)
46
- p2.password = "another secret"
47
- _(p2.algorithm).must_be_instance_of(HTAuth::Crypt)
48
- end
49
-
50
- it "encrypts with md5 as default, when parsed from an md5 line" do
51
- m = HTAuth::PasswdEntry.new("mary", "m secret", "md5")
52
- m2 = HTAuth::PasswdEntry.from_line(m.to_s)
53
- _(m2.algorithm).must_be_instance_of(HTAuth::Md5)
54
- end
55
-
56
- it "encrypts with sha1 as default, when parsed from an sha1 line" do
57
- s = HTAuth::PasswdEntry.new("steve", "s secret", "sha1")
58
- s2 = HTAuth::PasswdEntry.from_line(s.to_s)
59
- _(s2.algorithm).must_be_instance_of(HTAuth::Sha1)
60
- end
61
-
62
- it "encrypts with bcrypt as default when parsed from a bcrypt line" do
63
- b = HTAuth::PasswdEntry.new("brenda", "b secret", "bcrypt")
64
- b2 = HTAuth::PasswdEntry.from_line(b.to_s)
65
- _(b2.algorithm).must_be_instance_of(HTAuth::Bcrypt)
66
- end
67
-
68
- it "determins the algorithm to be crypt when checking a password" do
69
- bob2 = HTAuth::PasswdEntry.from_line(@bob.to_s)
70
- _(bob2.algorithm).must_be_instance_of(HTAuth::Crypt)
71
- _(bob2.authenticated?("b secret")).must_equal true
72
- _(bob2.algorithm).must_be_instance_of(HTAuth::Crypt)
73
- end
74
-
75
- it "determins the algorithm to be plain when checking a password" do
76
- bob2 = HTAuth::PasswdEntry.from_line("bob:b secret")
77
- _(bob2.algorithm).must_be_instance_of(HTAuth::Plaintext)
78
- _(bob2.authenticated?("b secret")).must_equal true
79
- _(bob2.algorithm).must_be_instance_of(HTAuth::Plaintext)
80
- end
81
-
82
- it "authenticates correctly against md5" do
83
- m = HTAuth::PasswdEntry.new("mary", "m secret", "md5")
84
- m2 = HTAuth::PasswdEntry.from_line(m.to_s)
85
- _(m2.authenticated?("m secret")).must_equal true
86
- end
87
-
88
- it "authenticates correctly against sha1" do
89
- s = HTAuth::PasswdEntry.new("steve", "s secret", "sha1")
90
- s2 = HTAuth::PasswdEntry.from_line(s.to_s)
91
- _(s2.authenticated?("s secret")).must_equal true
92
- end
93
-
94
- it "authenticates correctly against bcrypt" do
95
- s = HTAuth::PasswdEntry.new("brenda", "b secret", "bcrypt")
96
- s2 = HTAuth::PasswdEntry.from_line(s.to_s)
97
- _(s2.authenticated?("b secret")).must_equal true
98
- end
99
-
100
- it "can update the cost of an entry after initialization before encoding password" do
101
- s = HTAuth::PasswdEntry.new("brenda", "b secret", "bcrypt")
102
- _(s.algorithm.cost).must_equal(::HTAuth::Bcrypt::DEFAULT_APACHE_COST)
103
-
104
- s2 = HTAuth::PasswdEntry.from_line(s.to_s)
105
- s2.algorithm_args = { :cost => 12 }
106
- s2.password = "b secret" # forces recalculation
107
-
108
- _(s2.algorithm.cost).must_equal(12)
109
- end
110
-
111
- it "raises an error if assinging an invalid algorithm" do
112
- b = HTAuth::PasswdEntry.new("brenda", "b secret", "bcrypt")
113
- _ { b.algorithm = 42 }.must_raise(HTAuth::InvalidAlgorithmError)
114
- end
115
-
116
- it "returns username for a key" do
117
- _(@alice.key).must_equal "alice"
118
- end
119
-
120
- it "checks the password correctly" do
121
- _(@bob.authenticated?("b secret")).must_equal true
122
- end
123
-
124
- it "formats correctly when put to a string" do
125
- _(@bob.to_s).must_equal "bob:b8Ml4Jp9I0N8E"
126
- end
127
-
128
- it "parses an input line" do
129
- @bob_new = HTAuth::PasswdEntry.from_line("bob:b8Ml4Jp9I0N8E")
130
- _(@bob.user).must_equal @bob_new.user
131
- _(@bob.digest).must_equal @bob_new.digest
132
- end
133
-
134
- it "knows if an input line is a possible entry and raises an exception" do
135
- _ { HTAuth::PasswdEntry.is_entry!("#stuff") }.must_raise(HTAuth::InvalidPasswdEntry)
136
- _ { HTAuth::PasswdEntry.is_entry!("this:that:other:stuff") }.must_raise(HTAuth::InvalidPasswdEntry)
137
- _ { HTAuth::PasswdEntry.is_entry!("this:that:other") }.must_raise(HTAuth::InvalidPasswdEntry)
138
- _ { HTAuth::PasswdEntry.is_entry!("this:that:0a90549e8ffb2dd62f98252a95d88xyz") }.must_raise(HTAuth::InvalidPasswdEntry)
139
- end
140
-
141
- it "knows if an input line is a possible entry and returns false" do
142
- _(HTAuth::PasswdEntry.is_entry?("#stuff")).must_equal false
143
- _(HTAuth::PasswdEntry.is_entry?("this:that:other:stuff")).must_equal false
144
- _(HTAuth::PasswdEntry.is_entry?("this:that:other")).must_equal false
145
- _(HTAuth::PasswdEntry.is_entry?("this:that:0a90549e8ffb2dd62f98252a95d88xyz")).must_equal false
146
- end
147
-
148
- it "knows if an input line is a possible entry and returns true" do
149
- _(HTAuth::PasswdEntry.is_entry?("bob:irRm0g.SDfCyI")).must_equal true
150
- _(HTAuth::PasswdEntry.is_entry?("bob:b secreat")).must_equal true
151
- _(HTAuth::PasswdEntry.is_entry?("bob:{SHA}b/tjGXbX80MEKVnF200S43ca4hY=")).must_equal true
152
- _(HTAuth::PasswdEntry.is_entry?("bob:$apr1$lo1tk/..$CarApvZPee0F6Wj1U0GxZ1")).must_equal true
153
- _(HTAuth::PasswdEntry.is_entry?("bob:$2y$05$ts3k1r.t0Cne6j6DLt0/SepT5X4qthDFEdfqHBBMO5MhqzyMz34j2")).must_equal true
154
- end
155
-
156
- it "duplicates itself" do
157
- _(@alice.dup.to_s).must_equal @alice.to_s
158
- end
159
- end
@@ -1,84 +0,0 @@
1
- require 'spec_helper'
2
- require 'htauth/passwd_file'
3
- require 'tempfile'
4
-
5
- describe HTAuth::PasswdFile do
6
-
7
- before(:each) do
8
- @tf = Tempfile.new("rpasswrd-passwd")
9
- @tf.write(IO.read(PASSWD_ORIGINAL_TEST_FILE))
10
- @tf.close
11
- @passwd_file = HTAuth::PasswdFile.new(@tf.path)
12
-
13
- @tf2 = Tempfile.new("rpasswrd-passwd-empty")
14
- @tf2.close
15
- @empty_passwd_file = HTAuth::PasswdFile.new(@tf2.path)
16
- end
17
-
18
- after(:each) do
19
- @tf2.close(true)
20
- @tf.close(true)
21
- end
22
-
23
- it "can add a new entry to an already existing passwd file" do
24
- @passwd_file.add_or_update("charlie", "c secret", "sha1")
25
- _(@passwd_file.contents).must_equal IO.read(PASSWD_ADD_TEST_FILE)
26
- end
27
-
28
- it "can tell if an entry already exists in the passwd file" do
29
- _(@passwd_file.has_entry?("alice")).must_equal true
30
- _(@passwd_file.has_entry?("david")).must_equal false
31
- end
32
-
33
- it "can update an entry in an already existing passwd file, algorithm can change" do
34
- @passwd_file.add_or_update("alice", "a new secret", "sha1")
35
- _(@passwd_file.contents).must_equal IO.read(PASSWD_UPDATE_TEST_FILE)
36
- end
37
-
38
- it "can update an entry in an already existing passwd file, algorithm and arguments can change" do
39
- @passwd_file.add_or_update("brenda", "b secret", "bcrypt")
40
- entry = @passwd_file.fetch("brenda")
41
- _(entry.algorithm.cost).must_equal(::HTAuth::Bcrypt::DEFAULT_APACHE_COST)
42
- @passwd_file.add_or_update("brenda", "b secret", "bcrypt", :cost => 12)
43
- entry = @passwd_file.fetch("brenda")
44
- _(entry.algorithm.cost).must_equal(12)
45
- end
46
-
47
- it "fetches a copy of an entry" do
48
- _(@passwd_file.fetch("alice").to_s).must_equal "alice:$apr1$DghnA...$CsPcgerfsI/Ryy0AOAJtb0"
49
- end
50
-
51
- it "raises an error if an attempt is made to alter a non-existent file" do
52
- _ { HTAuth::PasswdFile.new("some-file") }.must_raise(HTAuth::FileAccessError)
53
- end
54
-
55
- # this test will only work on systems that have /etc/ssh_host_rsa_key
56
- it "raises an error if an attempt is made to open a file where no permissions are granted" do
57
- _ { HTAuth::PasswdFile.new("/etc/ssh_host_rsa_key") }.must_raise(HTAuth::FileAccessError)
58
- end
59
-
60
- it "deletes an entry" do
61
- @passwd_file.delete("bob")
62
- _(@passwd_file.contents).must_equal IO.read(PASSWD_DELETE_TEST_FILE)
63
- end
64
-
65
- it "checks authentication of an entry - true" do
66
- _(@passwd_file.authenticated?("alice", "a secret")).must_equal true
67
- end
68
-
69
- it "checks authentication of an entry - false" do
70
- _(@passwd_file.authenticated?("alice", "the wrong secret")).must_equal false
71
- end
72
-
73
-
74
- it "is usable in a ruby manner and yields itself when opened" do
75
- HTAuth::PasswdFile.open(@tf.path) do |pf|
76
- pf.add_or_update("alice", "a new secret", "md5")
77
- pf.delete('bob')
78
- end
79
- lines = IO.readlines(@tf.path)
80
- _(lines.size).must_equal 1
81
- _(lines.first.split(':').first).must_equal "alice"
82
- _(lines.first.split(':').last).must_match( /\$apr1\$/ )
83
- end
84
- end
@@ -1,11 +0,0 @@
1
- require 'spec_helper'
2
- require 'htauth/plaintext'
3
-
4
- describe HTAuth::Plaintext do
5
- it "encrypts the same way that apache does" do
6
- apache_result = "a secret"
7
- pt = HTAuth::Plaintext.new
8
- _(pt.encode("a secret")).must_equal apache_result
9
- end
10
- end
11
-
data/spec/sha1_spec.rb DELETED
@@ -1,11 +0,0 @@
1
- require 'spec_helper'
2
- require 'htauth/sha1'
3
-
4
- describe HTAuth::Sha1 do
5
- it "encrypts the same way that apache does" do
6
- apache_result = "{SHA}ZrnlrvmM7ZCOV3FAvM7la89NKbk="
7
- sha1 = HTAuth::Sha1.new
8
- _(sha1.encode("a secret")).must_equal apache_result
9
- end
10
- end
11
-
data/spec/spec_helper.rb DELETED
@@ -1,28 +0,0 @@
1
- if RUBY_VERSION >= '1.9.2' then
2
- require 'simplecov'
3
- puts "Using coverage!"
4
- SimpleCov.start if ENV['COVERAGE']
5
- end
6
-
7
- gem 'minitest'
8
- require 'minitest/autorun'
9
- require 'minitest/pride'
10
-
11
- PASSWD_ORIGINAL_TEST_FILE = File.join(File.dirname(__FILE__), "test.original.passwd")
12
- PASSWD_ADD_TEST_FILE = File.join(File.dirname(__FILE__), "test.add.passwd")
13
- PASSWD_UPDATE_TEST_FILE = File.join(File.dirname(__FILE__), "test.update.passwd")
14
- PASSWD_DELETE_TEST_FILE = File.join(File.dirname(__FILE__), "test.delete.passwd")
15
- PASSWD_COMMENTED_TEST_FILE = File.join(File.dirname(__FILE__), "test.comments.passwd")
16
-
17
- DIGEST_ORIGINAL_TEST_FILE = File.join(File.dirname(__FILE__), "test.original.digest")
18
- DIGEST_ADD_TEST_FILE = File.join(File.dirname(__FILE__), "test.add.digest")
19
- DIGEST_UPDATE_TEST_FILE = File.join(File.dirname(__FILE__), "test.update.digest")
20
- DIGEST_DELETE_TEST_FILE = File.join(File.dirname(__FILE__), "test.delete.digest")
21
- DIGEST_COMMENTED_TEST_FILE = File.join(File.dirname(__FILE__), "test.comments.digest")
22
-
23
- require 'stringio'
24
- class ConsoleIO < StringIO
25
- def noecho(&block)
26
- yield self
27
- end
28
- end
data/spec/test.add.digest DELETED
@@ -1,3 +0,0 @@
1
- bob:htauth:fcbeab6821d2ab3b00934c958db0fd1e
2
- alice:htauth:2f361db93147d84831eb34f19d05bfbb
3
- charlie:htauth-new:1ec9da72c45d9140949f338dc537c089
data/spec/test.add.passwd DELETED
@@ -1,3 +0,0 @@
1
- alice:$apr1$DghnA...$CsPcgerfsI/Ryy0AOAJtb0
2
- bob:SFUkhjaJc18KA
3
- charlie:{SHA}Cqrkk2no+ly0vYClUp49OJQahSE=
@@ -1 +0,0 @@
1
- bob:htauth:fcbeab6821d2ab3b00934c958db0fd1e
@@ -1 +0,0 @@
1
- alice:$apr1$DghnA...$CsPcgerfsI/Ryy0AOAJtb0
@@ -1,2 +0,0 @@
1
- bob:htauth:fcbeab6821d2ab3b00934c958db0fd1e
2
- alice:htauth:2f361db93147d84831eb34f19d05bfbb
@@ -1,2 +0,0 @@
1
- alice:$apr1$DghnA...$CsPcgerfsI/Ryy0AOAJtb0
2
- bob:SFUkhjaJc18KA
@@ -1,2 +0,0 @@
1
- bob:htauth:fcbeab6821d2ab3b00934c958db0fd1e
2
- alice:htauth:c32a4df25c6ecf75f3eaeb96771520de
@@ -1,2 +0,0 @@
1
- alice:{SHA}GnoUUjgrLF07/6L9lW2BcaDXxB0=
2
- bob:SFUkhjaJc18KA
data/tasks/default.rake DELETED
@@ -1,242 +0,0 @@
1
- # vim: syntax=ruby
2
- require 'rake/clean'
3
- require 'digest'
4
- #------------------------------------------------------------------------------
5
- # If you want to Develop on this project just run 'rake develop' and you'll
6
- # have all you need to get going. If you want to use bundler for development,
7
- # then run 'rake develop:using_bundler'
8
- #------------------------------------------------------------------------------
9
- namespace :develop do
10
-
11
- # Install all the development and runtime dependencies of this gem using the
12
- # gemspec.
13
- task :default => 'Gemfile' do
14
- require 'rubygems/dependency_installer'
15
- installer = ::Gem::DependencyInstaller.new
16
- puts "Installing bundler..."
17
- installer.install 'bundler'
18
- sh 'bundle install'
19
- puts "\n\nNow run 'rake test'"
20
- end
21
-
22
- # Create a Gemfile that just references the gemspec
23
- file 'Gemfile' => :gemspec do
24
- File.open( "Gemfile", "w+" ) do |f|
25
- f.puts "# DO NOT EDIT - This file is automatically generated"
26
- f.puts "# Make changes to Manifest.txt and/or Rakefile and regenerate"
27
- f.puts 'source "https://rubygems.org"'
28
- f.puts 'gemspec'
29
- end
30
- end
31
- end
32
- desc "Bootstrap development"
33
- task :develop => "develop:default"
34
-
35
- #------------------------------------------------------------------------------
36
- # Minitest - standard TestTask
37
- #------------------------------------------------------------------------------
38
- begin
39
- require 'rake/testtask'
40
- Rake::TestTask.new( :test ) do |t|
41
- t.ruby_opts = %w[ -w ]
42
- t.libs = %w[ lib spec test ]
43
- t.pattern = "{test,spec}/**/{test_*,*_spec}.rb"
44
- end
45
-
46
- task :test_requirements
47
- task :test => :test_requirements
48
- task :default => :test
49
- rescue LoadError
50
- This.task_warning( 'test' )
51
- end
52
-
53
- #------------------------------------------------------------------------------
54
- # RDoc - standard rdoc rake task, although we must make sure to use a more
55
- # recent version of rdoc since it is the one that has 'tomdoc' markup
56
- #------------------------------------------------------------------------------
57
- begin
58
- gem 'rdoc' # otherwise we get the wrong task from stdlib
59
- require 'rdoc/task'
60
- RDoc::Task.new do |t|
61
- t.markup = 'tomdoc'
62
- t.rdoc_dir = 'doc'
63
- t.main = 'README.md'
64
- t.title = "#{This.name} #{This.version}"
65
- t.rdoc_files.include( FileList['*.{rdoc,md,txt}'], FileList['ext/**/*.c'],
66
- FileList['lib/**/*.rb'] )
67
- end
68
- rescue StandardError, LoadError
69
- This.task_warning( 'rdoc' )
70
- end
71
-
72
- #------------------------------------------------------------------------------
73
- # Coverage - optional code coverage, rcov for 1.8 and simplecov for 1.9, so
74
- # for the moment only rcov is listed.
75
- #------------------------------------------------------------------------------
76
- begin
77
- require 'simplecov'
78
- desc 'Run tests with code coverage'
79
- task :coverage do
80
- ENV['COVERAGE'] = 'true'
81
- Rake::Task[:test].execute
82
- end
83
- CLOBBER << 'coverage' if File.directory?( 'coverage' )
84
- rescue LoadError
85
- This.task_warning( 'simplecov' )
86
- end
87
-
88
- #------------------------------------------------------------------------------
89
- # Manifest - We want an explicit list of thos files that are to be packaged in
90
- # the gem. Most of this is from Hoe.
91
- #------------------------------------------------------------------------------
92
- namespace 'manifest' do
93
- desc "Check the manifest"
94
- task :check => :clean do
95
- files = FileList["**/*", ".*"].exclude( This.exclude_from_manifest ).to_a.sort
96
- files = files.select{ |f| File.file?( f ) }
97
-
98
- tmp = "Manifest.tmp"
99
- File.open( tmp, 'w' ) do |f|
100
- f.puts files.join("\n")
101
- end
102
-
103
- begin
104
- sh "diff -du Manifest.txt #{tmp}"
105
- ensure
106
- rm tmp
107
- end
108
- puts "Manifest looks good"
109
- end
110
-
111
- desc "Generate the manifest"
112
- task :generate => :clean do
113
- files = %x[ git ls-files ].split("\n").sort
114
- files.reject! { |f| f =~ This.exclude_from_manifest }
115
- File.open( "Manifest.txt", "w" ) do |f|
116
- f.puts files.join("\n")
117
- end
118
- end
119
- end
120
-
121
- #------------------------------------------------------------------------------
122
- # Fixme - look for fixmes and report them
123
- #------------------------------------------------------------------------------
124
- namespace :fixme do
125
- task :default => 'manifest:check' do
126
- This.manifest.each do |file|
127
- next if file == __FILE__
128
- next unless file =~ %r/(txt|rb|md|rdoc|css|html|xml|css)\Z/
129
- puts "FIXME: Rename #{file}" if file =~ /fixme/i
130
- IO.readlines( file ).each_with_index do |line, idx|
131
- prefix = "FIXME: #{file}:#{idx+1}".ljust(42)
132
- puts "#{prefix} => #{line.strip}" if line =~ /fixme/i
133
- end
134
- end
135
- end
136
-
137
- def fixme_project_root
138
- This.project_path( '../fixme' )
139
- end
140
-
141
- def fixme_project_path( subtree )
142
- fixme_project_root.join( subtree )
143
- end
144
-
145
- def local_fixme_files
146
- This.manifest.select { |p| p =~ %r|^tasks/| }
147
- end
148
-
149
- def outdated_fixme_files
150
- local_fixme_files.select do |local|
151
- upstream = fixme_project_path( local )
152
- upstream.exist? &&
153
- ( Digest::SHA256.file( local ) != Digest::SHA256.file( upstream ) )
154
- end
155
- end
156
-
157
- def fixme_up_to_date?
158
- outdated_fixme_files.empty?
159
- end
160
-
161
- desc "See if the fixme tools are outdated"
162
- task :outdated do
163
- if fixme_up_to_date? then
164
- puts "Fixme files are up to date."
165
- else
166
- outdated_fixme_files.each do |f|
167
- puts "#{f} is outdated"
168
- end
169
- end
170
- end
171
-
172
- desc "Update outdated fixme files"
173
- task :update do
174
- if fixme_up_to_date? then
175
- puts "Fixme files are already up to date."
176
- else
177
- puts "Updating fixme files:"
178
- outdated_fixme_files.each do |local|
179
- upstream = fixme_project_path( local )
180
- puts " * #{local}"
181
- FileUtils.cp( upstream, local )
182
- end
183
- puts "Use your git commands as appropriate."
184
- end
185
- end
186
- end
187
- desc "Look for fixmes and report them"
188
- task :fixme => "fixme:default"
189
-
190
- #------------------------------------------------------------------------------
191
- # Gem Specification
192
- #------------------------------------------------------------------------------
193
- # Really this is only here to support those who use bundler
194
- desc "Build the #{This.name}.gemspec file"
195
- task :gemspec do
196
- File.open( This.gemspec_file, "wb+" ) do |f|
197
- f.puts "# DO NOT EDIT - This file is automatically generated"
198
- f.puts "# Make changes to Manifest.txt and/or Rakefile and regenerate"
199
- f.write This.platform_gemspec.to_ruby
200
- end
201
- end
202
-
203
- # .rbc files from ruby 2.0
204
- CLOBBER << FileList["**/*.rbc"]
205
-
206
- # The standard gem packaging task, everyone has it.
207
- require 'rubygems/package_task'
208
- ::Gem::PackageTask.new( This.platform_gemspec ) do
209
- # nothing
210
- end
211
-
212
- #------------------------------------------------------------------------------
213
- # Release - the steps we go through to do a final release, this is pulled from
214
- # a compbination of mojombo's rakegem, hoe and hoe-git
215
- #
216
- # 1) make sure we are on the main branch
217
- # 2) make sure there are no uncommitted items
218
- # 3) check the manifest and make sure all looks good
219
- # 4) build the gem
220
- # 5) do an empty commit to have the commit message of the version
221
- # 6) tag that commit as the version
222
- # 7) push main
223
- # 8) push the tag
224
- # 7) pus the gem
225
- #------------------------------------------------------------------------------
226
- task :release_check do
227
- unless `git branch` =~ /^\* main/
228
- abort "You must be on the main branch to release!"
229
- end
230
- unless `git status` =~ /^nothing to commit/m
231
- abort "Nope, sorry, you have unfinished business"
232
- end
233
- end
234
-
235
- desc "Create tag v#{This.version}, build and push #{This.platform_gemspec.full_name} to rubygems.org"
236
- task :release => [ :release_check, 'manifest:check', :gem ] do
237
- sh "git commit --allow-empty -a -m 'Release #{This.version}'"
238
- sh "git tag -a -m 'v#{This.version}' v#{This.version}"
239
- sh "git push origin main"
240
- sh "git push origin v#{This.version}"
241
- sh "gem push pkg/#{This.platform_gemspec.full_name}.gem"
242
- end