class ASF::ICLA
Provide access to the contents of iclas.txt.
N.B. only id and name should be considered public form and claRef may contain details of the legal name beyond that in the public name
Constants
- OFFICERS
-
location of a working copy of the officers directory in
SVN
- SOURCE
-
location of the iclas.txt file; may be
nil
if not found. - SOURCE_URL
Attributes
cla name or SVN
revision info; extracted from the form
email address from the ICLA
(may include multiple values, separated by space or comma)
lists the name of the form on file; includes claRef information
legal name for the individual; should not be shared
Public Class Methods
Source
# File lib/whimsy/asf/icla.rb, line 131 def self.array_count_match(source, target) count = 0 source.each {|src| count += 1 if target.include? src} count end
find number of matches in target array
Source
# File lib/whimsy/asf/icla.rb, line 293 def self.available?(id) return !self.taken?(id) end
is the id available? See also ASF::Mail.taken?
Source
# File lib/whimsy/asf/icla.rb, line 161 def self.availids return [] unless SOURCE refresh return @@availids if @@availids availids = [] each {|icla| availids << icla.id unless icla.id == 'notinavail'} @@availids = availids end
list of all ids
Source
# File lib/whimsy/asf/icla.rb, line 270 def self.availids_reserved return @@availids_reserved if @@availids_reserved reserved = File.read(File.join(ASF::SVN['officers'], 'reserved-ids.yml')).scan(/^- (\S+)/).flatten.uniq # Add in badrcptto reserved += self.badmails @@availids_reserved = reserved.uniq end
list of reserved availids
Source
# File lib/whimsy/asf/icla.rb, line 280 def self.availids_taken self.availids_reserved + self.availids end
list of all availids that are are taken or reserved See also ASF::Mail.taken?
Source
# File lib/whimsy/asf/icla.rb, line 241 def self.badmails qmc = File.join(ASF::Config[:puppet_data], 'qmail_control') # non-patterns brt = File.join(qmc, 'badrcptto') badmails = File.read(brt).scan(/^(\w.+)@apache\.org\s*$/).flatten # now parse patterns brtpat = File.join(qmc, 'badrcptto_patterns') File.read(brtpat).each_line do |line| m = line.match(/^\^(\w.+)\\@/) if m badmails << m[1] next end # ^(abc|def|ghi)(jkl|mno|pqr)\@ m = line.match(/^\^\(([|\w]+)\)\(([|\w]+)\)\\@/) if m m[1].split('|').each do |one| m[2].split('|').each do |two| badmails << "#{one}#{two}" end end else Wunderbar.warn "Error parsing #{brtpat} : could not match #{line}" end end badmails.uniq end
list of mails rejected by badrcptto and badrcptto_patterns Not intended for external use
Source
# File lib/whimsy/asf/icla.rb, line 171 def self.each(&block) refresh if @@icla_index and not @@icla_index.empty? @@icla_index.each(&block) elsif SOURCE and File.exist?(SOURCE) @@icla_index = [] File.read(SOURCE).scan(/^([-\w]+):(.*?):(.*?):(.*?):(.*)/).each do |list| icla = ICLA.new() icla.id = list[0] icla.legal_name = list[1] icla.name = list[2] icla.email = list[3] icla.form = list[4] match = icla.form.match(/^Signed CLA(?:;(\S+)| \((\+=.+)\))/) if match # match either the cla name or the SVN ref (+=...) icla.claRef = match[1] || match[2] end block.call(icla) @@icla_index << icla end end end
iterate over all of the ICLAs
Source
# File lib/whimsy/asf/icla.rb, line 93 def self.find_by_email(value) return unless SOURCE refresh unless @@email_index @@email_index = {} # Allow for multiple emails separated by comma or space each {|icla| icla.emails.each {|m| @@email_index[m.downcase] = icla}} end @@email_index[value.downcase] end
find ICLA
by email
Source
# File lib/whimsy/asf/icla.rb, line 80 def self.find_by_id(value) return if value == 'notinavail' or not SOURCE refresh unless @@id_index @@id_index = {} each {|icla| @@id_index[icla.id] = icla} end @@id_index[value] end
find ICLA
by ID
Source
# File lib/whimsy/asf/icla.rb, line 115 def self.find_by_name(value, multiple=false) return unless SOURCE refresh unless @@name_index # Collect all the entries for each matching name @@name_index = Hash.new {|h, k| h[k] = Array.new} each {|icla| @@name_index[icla.name] << icla } end entries = @@name_index[value] return entries if multiple # no filtering needed return entries.first if entries&.size == 1 return nil end
find ICLA
by (public) name There are multiple entries with the same name. So if there are multiple matches, it does not make sense to return a single entry. By default, only return an entry if there is a single match. (else nil) If the multiple param is true, return an array of all matching entries. The array may be empty; does not return nil.
N.B. matching by name is inherently inaccurate due to misspellings and duplicates. There are likely to be both false positives and false negatives. Use with caution!
Source
# File lib/whimsy/asf/icla.rb, line 138 def self.find_matches(value) matches = [] source = value.strip.downcase.split(' ') self.each do |icla| target = icla.legal_name.strip.downcase.split(' ') if target.sort == source.sort # order- and case-independent match matches << icla else cnt = self.array_count_match(source, target) if cnt >= 2 matches << icla else cnt = self.array_count_match(target, source) if cnt >= 2 matches << icla end end end end matches end
find close matches
Source
# File lib/whimsy/asf/icla.rb, line 215 def self.lname(line) return '' if line.start_with? '#' _, name, rest = line.split(':', 3) return '' unless name # Drop trailing (comment string) or /* comment */ name.sub!(/\(.+\)$/, '') name.sub!(/\/\*.+\*\/$/, '') return '' if name.strip.empty? name = ASF::Person.sortable_name(name) "#{name}:#{rest}" end
rearrange line in an order suitable for sorting
Source
# File lib/whimsy/asf/icla.rb, line 67 def self.preload people = [] each do |icla| unless icla.id == 'notinavail' person = ASF::Person.find(icla.id) people << person person.icla = icla end end people end
load ICLA
information for every committer
Source
# File lib/whimsy/asf/icla.rb, line 45 def self.refresh if not SOURCE or File.mtime(SOURCE) != @@mtime @@mtime = SOURCE ? File.mtime(SOURCE) : Time.now @@id_index = nil @@email_index = nil @@name_index = nil @@icla_index = nil # cache of all iclas as an array @@svn_change = nil @@availids = nil end end
flush caches if source file changed
Source
# File lib/whimsy/asf/icla.rb, line 231 def self.sort(source) headers = source.scan(/^#.*/) lines = source.scan(/^\w.*/) headers.join("\n") + "\n" + lines.sort_by {|line| lname(line + "\n")}.join("\n") + "\n" end
sort an entire iclas.txt
file
Source
# File lib/whimsy/asf/icla.rb, line 59 def self.svn_change self.refresh if SOURCE @@svn_change ||= Time.parse(ASF::SVN.getInfoItem(SOURCE, 'last-changed-date')).gmtime end end
Date and time of the last change in iclas.txt
in the working copy
Source
# File lib/whimsy/asf/icla.rb, line 286 def self.taken?(id) return self.availids_reserved.include?(id) || self.availids.include?(id) end
is the availid taken (in use or reserved)? See also ASF::Mail.taken?
Source
# File lib/whimsy/asf/icla.rb, line 197 def self.unlisted_name_by_email(age=0, env=nil) if age > 0 rev = '{%s}:HEAD' % (Date.today - age) diff, _err = ASF::SVN.svn('diff', SOURCE_URL, {revision: rev, env: env}) raise _err unless diff return Hash[*diff.scan(/^[+]notinavail:.*?:(.*?):(.*?):Signed CLA/).flatten.reverse] end hash = {} self.each { |icla| hash[icla.email] = icla.name if icla.noId? } hash end
return a hash of unlisted ICLA
names, keyed by email if age > 0, return the entries added in the last n days
Public Instance Methods
Source
# File lib/whimsy/asf/icla.rb, line 210 def as_line [id, legal_name, name, email, form].join(':') end
show the original entry (reconstructed for now)
Source
# File lib/whimsy/asf/icla.rb, line 303 def emails email.split(/[, ]/) end
return emails split by comma or space
Source
# File lib/whimsy/asf/icla.rb, line 298 def noId? self.id == 'notinavail' end
does the entry not have an id?