whimsy-asf 0.0.75 → 0.0.76
Sign up to get free protection for your applications and to get access to all the features.
- 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
|