whimsy-asf 0.0.75 → 0.0.76
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 +4 -4
- data/asf.version +1 -1
- data/lib/whimsy/asf/agenda/attachments.rb +1 -1
- data/lib/whimsy/asf/committee.rb +3 -9
- data/lib/whimsy/asf/icla.rb +18 -3
- data/lib/whimsy/asf/ldap.rb +127 -36
- data/lib/whimsy/asf/mail.rb +8 -3
- data/lib/whimsy/asf/member.rb +17 -8
- data/lib/whimsy/asf/nominees.rb +9 -3
- data/lib/whimsy/asf/rack.rb +5 -3
- data/lib/whimsy/asf/site.rb +4 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42ee442311d0fc054e4dd8fb6f2bdb4635d03ce1
|
4
|
+
data.tar.gz: d556f03175acf95b7882d59b1abfe0b3332c81b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a00c4fa7f49262e06d04cdffb11929b1955e27afb55b3bc5f2224703a1ccd3d6d609a3656e6a6a3d54677bfcd8e7191641e944888aeebc8359028ab33d7c57c
|
7
|
+
data.tar.gz: ed851c6a5edc6fef8325345c96d75d9abfaafa2b1e6753b2de2a8ff3d65ccdb30f35f5bbc74fc0912eb2cdd87227c27d08c4564610b753a06e84721638b2525c
|
data/asf.version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.76
|
@@ -35,7 +35,7 @@ class ASF::Board::Agenda
|
|
35
35
|
unless @quick
|
36
36
|
begin
|
37
37
|
committee = ASF::Committee.find(attrs['title'])
|
38
|
-
attrs['chair_email'] = committee.chair.
|
38
|
+
attrs['chair_email'] = "#{committee.chair.id}@apache.org"
|
39
39
|
attrs['mail_list'] = committee.mail_list
|
40
40
|
attrs.delete('mail_list') if attrs['mail_list'].include? ' '
|
41
41
|
|
data/lib/whimsy/asf/committee.rb
CHANGED
@@ -6,11 +6,10 @@ module ASF
|
|
6
6
|
end
|
7
7
|
|
8
8
|
class Committee < Base
|
9
|
-
attr_accessor :info, :
|
9
|
+
attr_accessor :info, :report, :roster, :established, :chairs,
|
10
10
|
:schedule
|
11
11
|
def initialize(*args)
|
12
12
|
@info = []
|
13
|
-
@emeritus = []
|
14
13
|
@chairs = []
|
15
14
|
@roster = {}
|
16
15
|
super
|
@@ -49,12 +48,12 @@ module ASF
|
|
49
48
|
file = "#{board}/committee-info.txt"
|
50
49
|
return unless File.exist? file
|
51
50
|
|
52
|
-
list = Hash.new {|hash, name| hash[name] = find(name)}
|
53
|
-
|
54
51
|
if @committee_info and File.mtime(file) == @committee_mtime
|
55
52
|
return @committee_info
|
56
53
|
end
|
57
54
|
|
55
|
+
list = Hash.new {|hash, name| hash[name] = find(name)}
|
56
|
+
|
58
57
|
@committee_mtime = File.mtime(file)
|
59
58
|
@@svn_change = Time.parse(
|
60
59
|
`svn info #{file}`[/Last Changed Date: (.*) \(/, 1]).gmtime
|
@@ -86,11 +85,6 @@ module ASF
|
|
86
85
|
committee = list[@@namemap.call(roster[/(\w.*?)\s+\(/,1])]
|
87
86
|
# get the start date
|
88
87
|
committee.established = roster[/\(est\. (.*?)\)/, 1]
|
89
|
-
# Extract any emeritus members (now probably redundant)
|
90
|
-
roster.gsub! /^.*\(\s*emeritus\s*\).*/i do |line|
|
91
|
-
committee.emeritus += line.scan(/<(.*?)@apache\.org>/).flatten
|
92
|
-
''
|
93
|
-
end
|
94
88
|
# extract the availids (is this used?)
|
95
89
|
committee.info = roster.scan(/<(.*?)@apache\.org>/).flatten
|
96
90
|
# drop (chair) markers and extract 0: name, 1: availid, 2: [date], 3: date
|
data/lib/whimsy/asf/icla.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
module ASF
|
2
2
|
|
3
3
|
class ICLA
|
4
|
-
|
4
|
+
# N.B. only id and name should be considered public
|
5
|
+
# form and claRef may contain details of the legal name beyond that in the public name
|
6
|
+
attr_accessor :id, :legal_name, :name, :email, :form
|
7
|
+
attr_accessor :claRef # cla name or SVN revision info
|
5
8
|
|
6
9
|
@@mtime = nil
|
7
10
|
|
@@ -31,9 +34,15 @@ module ASF
|
|
31
34
|
|
32
35
|
# load ICLA information for every committer
|
33
36
|
def self.preload
|
37
|
+
people = []
|
34
38
|
each do |icla|
|
35
|
-
|
39
|
+
unless icla.id == 'notinaval'
|
40
|
+
person = ASF::Person.find(icla.id)
|
41
|
+
people << person
|
42
|
+
person.icla = icla
|
43
|
+
end
|
36
44
|
end
|
45
|
+
people
|
37
46
|
end
|
38
47
|
|
39
48
|
# find ICLA by ID
|
@@ -94,12 +103,18 @@ module ASF
|
|
94
103
|
elsif @@name_index and not @@name_index.empty?
|
95
104
|
@@name_index.values.each(&block)
|
96
105
|
elsif SOURCE and File.exist?(SOURCE)
|
97
|
-
File.read(SOURCE).scan(/^([-\w]+):(.*?):(.*?):(.*?)
|
106
|
+
File.read(SOURCE).scan(/^([-\w]+):(.*?):(.*?):(.*?):(.*)/).each do |list|
|
98
107
|
icla = ICLA.new()
|
99
108
|
icla.id = list[0]
|
100
109
|
icla.legal_name = list[1]
|
101
110
|
icla.name = list[2]
|
102
111
|
icla.email = list[3]
|
112
|
+
icla.form = list[4]
|
113
|
+
match = icla.form.match(/^Signed CLA(?:;(\S+)| \((\+=.+)\))/)
|
114
|
+
if match
|
115
|
+
# match either the cla name or the SVN ref (+=...)
|
116
|
+
icla.claRef = match[1] || match[2]
|
117
|
+
end
|
103
118
|
block.call(icla)
|
104
119
|
end
|
105
120
|
end
|
data/lib/whimsy/asf/ldap.rb
CHANGED
@@ -33,6 +33,7 @@ require 'ldap'
|
|
33
33
|
require 'weakref'
|
34
34
|
require 'net/http'
|
35
35
|
require 'base64'
|
36
|
+
require 'thread'
|
36
37
|
|
37
38
|
module ASF
|
38
39
|
module LDAP
|
@@ -48,6 +49,9 @@ module ASF
|
|
48
49
|
ldaps://ldap2-lw-eu.apache.org:636
|
49
50
|
)
|
50
51
|
|
52
|
+
CONNECT_LOCK = Mutex.new
|
53
|
+
HOST_QUEUE = Queue.new
|
54
|
+
|
51
55
|
# fetch configuration from apache/infrastructure-puppet
|
52
56
|
def self.puppet_config
|
53
57
|
return @puppet if @puppet
|
@@ -71,8 +75,13 @@ module ASF
|
|
71
75
|
end
|
72
76
|
|
73
77
|
# connect to LDAP
|
74
|
-
def self.connect
|
75
|
-
|
78
|
+
def self.connect(test = true)
|
79
|
+
# Try each host at most once
|
80
|
+
hosts.length.times do
|
81
|
+
# Ensure we use each host in turn
|
82
|
+
hosts.each {|host| HOST_QUEUE.push host} if HOST_QUEUE.empty?
|
83
|
+
host = HOST_QUEUE.shift
|
84
|
+
|
76
85
|
Wunderbar.info "Connecting to LDAP server: #{host}"
|
77
86
|
|
78
87
|
begin
|
@@ -85,7 +94,7 @@ module ASF
|
|
85
94
|
end
|
86
95
|
|
87
96
|
# test the connection
|
88
|
-
ldap.bind
|
97
|
+
ldap.bind if test
|
89
98
|
|
90
99
|
# save the host
|
91
100
|
@host = host
|
@@ -97,14 +106,18 @@ module ASF
|
|
97
106
|
end
|
98
107
|
|
99
108
|
end
|
109
|
+
|
100
110
|
Wunderbar.error "Failed to connect to any LDAP host"
|
101
111
|
return nil
|
102
112
|
end
|
103
113
|
end
|
104
114
|
|
105
|
-
#
|
106
|
-
def self.init_ldap
|
107
|
-
|
115
|
+
# public entry point for establishing a connection safely
|
116
|
+
def self.init_ldap(reset = false)
|
117
|
+
ASF::LDAP::CONNECT_LOCK.synchronize do
|
118
|
+
@ldap = nil if reset
|
119
|
+
@ldap ||= ASF::LDAP.connect(!reset)
|
120
|
+
end
|
108
121
|
end
|
109
122
|
|
110
123
|
# determine where ldap.conf resides
|
@@ -118,23 +131,39 @@ module ASF
|
|
118
131
|
@ldap || self.init_ldap
|
119
132
|
end
|
120
133
|
|
121
|
-
# search with a scope of one
|
134
|
+
# search with a scope of one, with automatic retry/failover
|
122
135
|
def self.search_one(base, filter, attrs=nil)
|
123
|
-
init_ldap unless defined? @ldap
|
124
|
-
return [] unless @ldap
|
125
136
|
|
126
|
-
|
137
|
+
cmd = "ldapsearch -x -LLL -b #{base} -s one #{filter} " +
|
127
138
|
"#{[attrs].flatten.join(' ')}"
|
128
|
-
|
139
|
+
|
140
|
+
# try once per host, with a minimum of two tries
|
141
|
+
attempts_left = [ASF::LDAP.hosts.length, 2].max
|
129
142
|
begin
|
143
|
+
attempts_left -= 1
|
144
|
+
init_ldap unless @ldap
|
145
|
+
return [] unless @ldap
|
146
|
+
|
147
|
+
target = @ldap.get_option(::LDAP::LDAP_OPT_HOST_NAME) rescue '?'
|
148
|
+
Wunderbar.info "[#{target}] #{cmd}"
|
149
|
+
|
130
150
|
result = @ldap.search2(base, ::LDAP::LDAP_SCOPE_ONELEVEL, filter, attrs)
|
131
|
-
rescue
|
132
|
-
|
151
|
+
rescue Exception => re
|
152
|
+
if attempts_left <= 0
|
153
|
+
Wunderbar.error "[#{target}] => #{re.inspect} for #{cmd}"
|
154
|
+
raise
|
155
|
+
else
|
156
|
+
Wunderbar.warn "[#{target}] => #{re.inspect} for #{cmd}, retrying ..."
|
157
|
+
@ldap.unbind if @ldap.bound? rescue nil
|
158
|
+
@ldap = nil # force new connection
|
159
|
+
sleep 1
|
160
|
+
retry
|
161
|
+
end
|
133
162
|
end
|
134
163
|
|
135
164
|
result.map! {|hash| hash[attrs]} if String === attrs
|
136
165
|
|
137
|
-
result
|
166
|
+
result.compact
|
138
167
|
end
|
139
168
|
|
140
169
|
# safely dereference a weakref array attribute. Block provided is
|
@@ -146,7 +175,9 @@ module ASF
|
|
146
175
|
rescue WeakRef::RefError
|
147
176
|
value = block.call
|
148
177
|
ensure
|
149
|
-
if value
|
178
|
+
if not value or RUBY_VERSION.start_with? '1'
|
179
|
+
object.instance_variable_set(attr, value)
|
180
|
+
elsif value and not value.instance_of? WeakRef
|
150
181
|
object.instance_variable_set(attr, WeakRef.new(value))
|
151
182
|
end
|
152
183
|
end
|
@@ -313,7 +344,7 @@ module ASF
|
|
313
344
|
end
|
314
345
|
|
315
346
|
def pgp_key_fingerprints
|
316
|
-
attrs['asf-pgpKeyFingerprint']
|
347
|
+
attrs['asf-pgpKeyFingerprint'] || []
|
317
348
|
end
|
318
349
|
|
319
350
|
def urls
|
@@ -383,17 +414,18 @@ module ASF
|
|
383
414
|
end
|
384
415
|
|
385
416
|
def self.preload
|
386
|
-
Hash[ASF.search_one(base, "cn=*", %w(dn memberUid modifyTimestamp)).map do |results|
|
417
|
+
Hash[ASF.search_one(base, "cn=*", %w(dn memberUid modifyTimestamp createTimestamp)).map do |results|
|
387
418
|
cn = results['dn'].first[/^cn=(.*?),/, 1]
|
388
419
|
group = ASF::Group.find(cn)
|
389
420
|
group.modifyTimestamp = results['modifyTimestamp'].first # it is returned as an array of 1 entry
|
390
|
-
|
391
|
-
|
421
|
+
group.createTimestamp = results['createTimestamp'].first # it is returned as an array of 1 entry
|
422
|
+
members = results['memberUid'] || []
|
423
|
+
group.members = members
|
392
424
|
[group, members]
|
393
425
|
end]
|
394
426
|
end
|
395
427
|
|
396
|
-
attr_accessor :modifyTimestamp
|
428
|
+
attr_accessor :modifyTimestamp, :createTimestamp
|
397
429
|
|
398
430
|
def members=(members)
|
399
431
|
@members = WeakRef.new(members)
|
@@ -406,6 +438,24 @@ module ASF
|
|
406
438
|
|
407
439
|
members.map {|uid| Person.find(uid)}
|
408
440
|
end
|
441
|
+
|
442
|
+
def dn
|
443
|
+
@dn ||= ASF.search_one(base, "cn=#{name}", 'dn').first.first
|
444
|
+
end
|
445
|
+
|
446
|
+
def remove(people)
|
447
|
+
people = Array(people).map(&:id)
|
448
|
+
mod = ::LDAP::Mod.new(::LDAP::LDAP_MOD_DELETE, 'memberUid', people)
|
449
|
+
ASF.ldap.modify(self.dn, [mod])
|
450
|
+
@members = nil
|
451
|
+
end
|
452
|
+
|
453
|
+
def add(people)
|
454
|
+
people = Array(people).map(&:dn)
|
455
|
+
mod = ::LDAP::Mod.new(::LDAP::LDAP_MOD_ADD, 'memberUid', people)
|
456
|
+
ASF.ldap.modify(self.dn, [mod])
|
457
|
+
@members = nil
|
458
|
+
end
|
409
459
|
end
|
410
460
|
|
411
461
|
class Committee < Base
|
@@ -416,17 +466,18 @@ module ASF
|
|
416
466
|
end
|
417
467
|
|
418
468
|
def self.preload
|
419
|
-
Hash[ASF.search_one(base, "cn=*", %w(dn member modifyTimestamp)).map do |results|
|
469
|
+
Hash[ASF.search_one(base, "cn=*", %w(dn member modifyTimestamp createTimestamp)).map do |results|
|
420
470
|
cn = results['dn'].first[/^cn=(.*?),/, 1]
|
421
471
|
committee = ASF::Committee.find(cn)
|
422
472
|
committee.modifyTimestamp = results['modifyTimestamp'].first # it is returned as an array of 1 entry
|
423
|
-
|
473
|
+
committee.createTimestamp = results['createTimestamp'].first # it is returned as an array of 1 entry
|
474
|
+
members = results['member'] || []
|
424
475
|
committee.members = members
|
425
476
|
[committee, members]
|
426
477
|
end]
|
427
478
|
end
|
428
479
|
|
429
|
-
attr_accessor :modifyTimestamp
|
480
|
+
attr_accessor :modifyTimestamp, :createTimestamp
|
430
481
|
|
431
482
|
def members=(members)
|
432
483
|
@members = WeakRef.new(members)
|
@@ -443,6 +494,20 @@ module ASF
|
|
443
494
|
def dn
|
444
495
|
@dn ||= ASF.search_one(base, "cn=#{name}", 'dn').first.first
|
445
496
|
end
|
497
|
+
|
498
|
+
def remove(people)
|
499
|
+
people = Array(people).map(&:dn)
|
500
|
+
mod = ::LDAP::Mod.new(::LDAP::LDAP_MOD_DELETE, 'member', people)
|
501
|
+
ASF.ldap.modify(self.dn, [mod])
|
502
|
+
@members = nil
|
503
|
+
end
|
504
|
+
|
505
|
+
def add(people)
|
506
|
+
people = Array(people).map(&:dn)
|
507
|
+
mod = ::LDAP::Mod.new(::LDAP::LDAP_MOD_ADD, 'member', people)
|
508
|
+
ASF.ldap.modify(self.dn, [mod])
|
509
|
+
@members = nil
|
510
|
+
end
|
446
511
|
end
|
447
512
|
|
448
513
|
class Service < Base
|
@@ -456,21 +521,44 @@ module ASF
|
|
456
521
|
"cn=#{id},#{self.class.base}"
|
457
522
|
end
|
458
523
|
|
524
|
+
def self.preload
|
525
|
+
Hash[ASF.search_one(base, "cn=*", %w(dn member modifyTimestamp createTimestamp)).map do |results|
|
526
|
+
cn = results['dn'].first[/^cn=(.*?),/, 1]
|
527
|
+
service = ASF::Service.find(cn)
|
528
|
+
service.modifyTimestamp = results['modifyTimestamp'].first # it is returned as an array of 1 entry
|
529
|
+
service.createTimestamp = results['createTimestamp'].first # it is returned as an array of 1 entry
|
530
|
+
members = results['member'] || []
|
531
|
+
service.members = members
|
532
|
+
[service, members]
|
533
|
+
end]
|
534
|
+
end
|
535
|
+
|
536
|
+
attr_accessor :modifyTimestamp, :createTimestamp
|
537
|
+
|
538
|
+
def members=(members)
|
539
|
+
@members = WeakRef.new(members)
|
540
|
+
end
|
541
|
+
|
459
542
|
def members
|
460
|
-
|
461
|
-
|
543
|
+
members = weakref(:members) do
|
544
|
+
ASF.search_one(base, "cn=#{name}", 'member').flatten
|
545
|
+
end
|
546
|
+
|
547
|
+
members.map {|uid| Person.find uid[/uid=(.*?),/,1]}
|
462
548
|
end
|
463
549
|
|
464
550
|
def remove(people)
|
465
551
|
people = Array(people).map(&:dn)
|
466
552
|
mod = ::LDAP::Mod.new(::LDAP::LDAP_MOD_DELETE, 'member', people)
|
467
553
|
ASF.ldap.modify(self.dn, [mod])
|
554
|
+
@members = nil
|
468
555
|
end
|
469
556
|
|
470
557
|
def add(people)
|
471
558
|
people = Array(people).map(&:dn)
|
472
559
|
mod = ::LDAP::Mod.new(::LDAP::LDAP_MOD_ADD, 'member', people)
|
473
560
|
ASF.ldap.modify(self.dn, [mod])
|
561
|
+
@members = nil
|
474
562
|
end
|
475
563
|
end
|
476
564
|
|
@@ -479,12 +567,13 @@ module ASF
|
|
479
567
|
dn = ASF::Person.new(user).dn
|
480
568
|
raise ::LDAP::ResultError.new('Unknown user') unless dn
|
481
569
|
|
482
|
-
ASF.ldap.unbind rescue nil
|
570
|
+
ASF.ldap.unbind if ASF.ldap.bound? rescue nil
|
571
|
+
ldap = ASF.init_ldap(true)
|
483
572
|
if block
|
484
|
-
|
485
|
-
ASF.init_ldap
|
573
|
+
ldap.bind(dn, password, &block)
|
574
|
+
ASF.init_ldap(true)
|
486
575
|
else
|
487
|
-
|
576
|
+
ldap.bind(dn, password)
|
488
577
|
end
|
489
578
|
end
|
490
579
|
|
@@ -509,6 +598,7 @@ module ASF
|
|
509
598
|
|
510
599
|
# determine what LDAP hosts are available
|
511
600
|
def self.hosts
|
601
|
+
return @hosts if @hosts # cache the hosts list
|
512
602
|
# try whimsy config
|
513
603
|
hosts = Array(ASF::Config.get(:ldap))
|
514
604
|
|
@@ -518,23 +608,24 @@ module ASF
|
|
518
608
|
if File.exist? conf
|
519
609
|
uris = File.read(conf)[/^uri\s+(.*)/i, 1].to_s
|
520
610
|
hosts = uris.scan(/ldaps?:\/\/\S+?:\d+/)
|
611
|
+
Wunderbar.debug "Using hosts from LDAP config"
|
521
612
|
end
|
613
|
+
else
|
614
|
+
Wunderbar.debug "Using hosts from Whimsy config"
|
522
615
|
end
|
523
616
|
|
524
617
|
# if all else fails, use default list
|
618
|
+
Wunderbar.debug "Using default host list" if hosts.empty?
|
525
619
|
hosts = ASF::LDAP::HOSTS if hosts.empty?
|
526
620
|
|
527
|
-
hosts
|
528
|
-
|
529
|
-
|
530
|
-
# select LDAP host
|
531
|
-
def self.host
|
532
|
-
@host ||= hosts.sample
|
621
|
+
hosts.shuffle!
|
622
|
+
#Wunderbar.debug "Hosts:\n#{hosts.join(' ')}"
|
623
|
+
@hosts = hosts
|
533
624
|
end
|
534
625
|
|
535
626
|
# query and extract cert from openssl output
|
536
627
|
def self.extract_cert
|
537
|
-
host =
|
628
|
+
host = hosts.sample[%r{//(.*?)(/|$)}, 1]
|
538
629
|
puts ['openssl', 's_client', '-connect', host, '-showcerts'].join(' ')
|
539
630
|
out, err, rc = Open3.capture3 'openssl', 's_client',
|
540
631
|
'-connect', host, '-showcerts'
|
data/lib/whimsy/asf/mail.rb
CHANGED
@@ -1,15 +1,19 @@
|
|
1
|
+
require 'weakref'
|
1
2
|
|
2
3
|
module ASF
|
3
4
|
|
4
5
|
class Mail
|
5
6
|
def self.list
|
6
|
-
|
7
|
+
begin
|
8
|
+
return Hash[@list.to_a] if @list
|
9
|
+
rescue NoMethodError, WeakRef::RefError
|
10
|
+
end
|
7
11
|
|
8
12
|
list = Hash.new
|
9
13
|
|
10
14
|
# load info from LDAP
|
11
15
|
people = ASF::Person.preload(['mail', 'asf-altEmail'])
|
12
|
-
people.each do |
|
16
|
+
people.each do |person|
|
13
17
|
(person.mail+person.alt_email).each do |mail|
|
14
18
|
list[mail.downcase] = person
|
15
19
|
end
|
@@ -28,7 +32,8 @@ module ASF
|
|
28
32
|
list["#{icla.id.downcase}@apache.org"] ||= person
|
29
33
|
end
|
30
34
|
|
31
|
-
@list = list
|
35
|
+
@list = WeakRef.new(list)
|
36
|
+
list
|
32
37
|
end
|
33
38
|
|
34
39
|
def self.lists(public_private= false)
|
data/lib/whimsy/asf/member.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'weakref'
|
2
|
+
|
1
3
|
module ASF
|
2
4
|
class Member
|
3
5
|
include Enumerable
|
@@ -15,10 +17,16 @@ module ASF
|
|
15
17
|
end
|
16
18
|
|
17
19
|
def self.list
|
18
|
-
result = Hash[self.new
|
20
|
+
result = Hash[self.new.map {|id, text|
|
21
|
+
# extract 1st line and remove any trailing /* comment */
|
22
|
+
name = text[/(.*?)\n/, 1].sub(/\s+\/\*.*/,'')
|
23
|
+
[id, {text: text, name: name}]
|
24
|
+
}]
|
25
|
+
|
19
26
|
self.status.each do |name, value|
|
20
27
|
result[name]['status'] = value
|
21
28
|
end
|
29
|
+
|
22
30
|
result
|
23
31
|
end
|
24
32
|
|
@@ -33,7 +41,11 @@ module ASF
|
|
33
41
|
end
|
34
42
|
|
35
43
|
def self.status
|
36
|
-
|
44
|
+
begin
|
45
|
+
return Hash[@status.to_a] if @status
|
46
|
+
rescue NoMethodError, WeakRef::RefError
|
47
|
+
end
|
48
|
+
|
37
49
|
status = {}
|
38
50
|
foundation = ASF::SVN['private/foundation']
|
39
51
|
return status unless foundation
|
@@ -43,18 +55,15 @@ module ASF
|
|
43
55
|
header.sub!(/s\n=+/,'')
|
44
56
|
text.scan(/Avail ID: (.*)/).flatten.each {|id| status[id] = header}
|
45
57
|
end
|
46
|
-
@status = status
|
47
|
-
end
|
48
58
|
|
49
|
-
|
50
|
-
|
59
|
+
@status = WeakRef.new(status)
|
60
|
+
status
|
51
61
|
end
|
52
62
|
|
53
63
|
def each
|
54
64
|
foundation = ASF::SVN['private/foundation']
|
55
65
|
File.read("#{foundation}/members.txt").split(/^ \*\) /).each do |section|
|
56
66
|
id = section[/Avail ID: (.*)/,1]
|
57
|
-
section = '' unless @full
|
58
67
|
yield id, section.sub(/\n.*\n===+\s*?\n(.*\n)+.*/,'').strip if id
|
59
68
|
end
|
60
69
|
nil
|
@@ -79,7 +88,7 @@ module ASF
|
|
79
88
|
|
80
89
|
class Person
|
81
90
|
def members_txt
|
82
|
-
@members_txt ||= ASF::Member.find_text_by_id(
|
91
|
+
@members_txt ||= ASF::Member.find_text_by_id(id)
|
83
92
|
end
|
84
93
|
|
85
94
|
def member_emails
|
data/lib/whimsy/asf/nominees.rb
CHANGED
@@ -1,9 +1,14 @@
|
|
1
|
+
require 'weakref'
|
2
|
+
|
1
3
|
module ASF
|
2
4
|
|
3
5
|
class Person < Base
|
4
6
|
|
5
7
|
def self.member_nominees
|
6
|
-
|
8
|
+
begin
|
9
|
+
return Hash[@member_nominees.to_a] if @member_nominees
|
10
|
+
rescue NoMethodError, WeakRef::RefError
|
11
|
+
end
|
7
12
|
|
8
13
|
meetings = ASF::SVN['private/foundation/Meetings']
|
9
14
|
nominations = Dir["#{meetings}/*/nominated-members.txt"].sort.last.untaint
|
@@ -22,11 +27,12 @@ module ASF
|
|
22
27
|
nominees[find(id)] = nomination
|
23
28
|
end
|
24
29
|
|
25
|
-
@member_nominees = nominees
|
30
|
+
@member_nominees = WeakRef.new(nominees)
|
31
|
+
nominees
|
26
32
|
end
|
27
33
|
|
28
34
|
def member_nomination
|
29
|
-
Person.member_nominees[self]
|
35
|
+
@member_nomination ||= Person.member_nominees[self]
|
30
36
|
end
|
31
37
|
end
|
32
38
|
end
|
data/lib/whimsy/asf/rack.rb
CHANGED
@@ -21,12 +21,14 @@ module ASF
|
|
21
21
|
def self.decode(env)
|
22
22
|
class << env; attr_accessor :user, :password; end
|
23
23
|
|
24
|
-
|
24
|
+
auth = env['HTTP_AUTHORIZATION'] || ENV['HTTP_AUTHORIZATION']
|
25
|
+
|
26
|
+
if auth.to_s.empty?
|
25
27
|
env.user = env['REMOTE_USER'] || ENV['USER'] || Etc.getpwuid.name
|
26
28
|
else
|
27
29
|
require 'base64'
|
28
|
-
env.user, env.password = Base64.
|
29
|
-
/^Basic ([A-Za-z0-9+\/=]+)$/,1].to_s).split(':',2)
|
30
|
+
env.user, env.password = Base64.
|
31
|
+
decode64(auth[/^Basic ([A-Za-z0-9+\/=]+)$/,1].to_s).split(':',2)
|
30
32
|
end
|
31
33
|
|
32
34
|
env['REMOTE_USER'] ||= env.user
|
data/lib/whimsy/asf/site.rb
CHANGED
@@ -52,6 +52,10 @@ module ASF
|
|
52
52
|
def self.list
|
53
53
|
templates = ASF::SVN['asf/infrastructure/site/trunk/content']
|
54
54
|
file = "#{templates}/index.html"
|
55
|
+
if not File.exist?(file)
|
56
|
+
Wunderbar.warn "Unable to find 'infrastructure/site/trunk/content'"
|
57
|
+
return {}
|
58
|
+
end
|
55
59
|
return @@list if not @@list.empty? and File.mtime(file) == @@mtime
|
56
60
|
@@mtime = File.mtime(file)
|
57
61
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: whimsy-asf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.76
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Ruby
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-02-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|