fix save_group and save_group_as
This commit is contained in:
parent
6e9300ee9b
commit
e7f301c90d
2 changed files with 84 additions and 19 deletions
|
|
@ -18,16 +18,19 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
require "set/intspan"
|
require "set/intspan"
|
||||||
|
#require "thread"
|
||||||
|
|
||||||
module News
|
module News
|
||||||
|
|
||||||
class Newsrc
|
class Newsrc
|
||||||
|
|
||||||
|
#@@save_lock = Mutex.new
|
||||||
|
|
||||||
def initialize(file=nil)
|
def initialize(file=nil)
|
||||||
@newsrc = { "group" => Hash.new, "list" => Array.new }
|
@newsrc = { "group" => Hash.new, "list" => Array.new }
|
||||||
if file
|
if file
|
||||||
unless load(file)
|
unless load(file)
|
||||||
print "Can't load #{file}\n"
|
puts "Can't load #{file}"
|
||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -58,7 +61,7 @@ end
|
||||||
|
|
||||||
def parse(line)
|
def parse(line)
|
||||||
unless line =~ /^([^!:]+)([!:])\s(.*)$/x
|
unless line =~ /^([^!:]+)([!:])\s(.*)$/x
|
||||||
print "Newsrc.parse: Bad newsrc line: #{line}\n"
|
puts "Newsrc.parse: Bad newsrc line: #{line}"
|
||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -67,7 +70,7 @@ def parse(line)
|
||||||
articles = $3
|
articles = $3
|
||||||
|
|
||||||
unless Set::IntSpan.valid(articles)
|
unless Set::IntSpan.valid(articles)
|
||||||
print "Newsrc.parse: Bad article list: #{line}\n"
|
puts "Newsrc.parse: Bad article list: #{line}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -85,49 +88,75 @@ def save
|
||||||
save_as(@newsrc["file"])
|
save_as(@newsrc["file"])
|
||||||
end
|
end
|
||||||
|
|
||||||
# this is not thread safe!
|
# this is not thread safe! (well, it should be now)
|
||||||
def save_as(file)
|
def save_as(file)
|
||||||
|
# @@save_lock.synchronize{
|
||||||
if FileTest.exists?("#{file}")
|
if FileTest.exists?("#{file}")
|
||||||
begin
|
begin
|
||||||
File.rename(file, "#{file}.bak")
|
File.rename(file, "#{file}.bak")
|
||||||
rescue
|
rescue
|
||||||
print "Can't rename #{file}, #{file}.bak: #{$!}\n"
|
puts "Can't rename #{file}, #{file}.bak: #{$!}"
|
||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
begin
|
begin
|
||||||
newsrc = File.new(file, "w")
|
newsrc = File.new(file, "w")
|
||||||
|
newsrc.flock(File::LOCK_EX)
|
||||||
rescue
|
rescue
|
||||||
print "Can't open #{file}: #{$!}\n"
|
puts "Can't open #{file}: #{$!}"
|
||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
@newsrc["file"] = file
|
@newsrc["file"] = file
|
||||||
@newsrc["list"].each{|group|
|
@newsrc["list"].each{|group|
|
||||||
newsrc.print format(group)
|
newsrc.print format(group)
|
||||||
}
|
}
|
||||||
|
newsrc.sync
|
||||||
|
newsrc.flock(File::LOCK_UN) # what's the right order here?
|
||||||
newsrc.close
|
newsrc.close
|
||||||
|
# }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Here 'group' is a group structure. It'd probably be much more useful if
|
||||||
|
# it could just be a group_name_; which it can now.
|
||||||
def save_group(group)
|
def save_group(group)
|
||||||
unless @newsrc.has_key?("file")
|
unless @newsrc.has_key?("file")
|
||||||
@newsrc["file"] = "#{$ENV['HOME']}/.newsrc"
|
@newsrc["file"] = "#{$ENV['HOME']}/.newsrc"
|
||||||
end
|
end
|
||||||
save_as(@newsrc["file"], group)
|
if group.class.to_s == "String"
|
||||||
|
groupname = group.dup
|
||||||
|
@newsrc["list"].each{|g|
|
||||||
|
if g["name"] == groupname
|
||||||
|
group = g.dup
|
||||||
|
break
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
end
|
||||||
|
save_group_as(@newsrc["file"], group)
|
||||||
end
|
end
|
||||||
|
|
||||||
# this should be thread safe
|
# This should be thread safe, but may not be. It needs testing!
|
||||||
|
# If not, mutexes are needed.
|
||||||
def save_group_as(file, group)
|
def save_group_as(file, group)
|
||||||
|
# @@save_lock.synchronize{
|
||||||
|
p Time.now
|
||||||
|
p "copy file"
|
||||||
if FileTest.exists?("#{file}")
|
if FileTest.exists?("#{file}")
|
||||||
if ( ! File.copy(file, "#{file}.bak") )
|
if ( ! File.copy(file, "#{file}.bak") )
|
||||||
print "Can't copy #{file} to #{file}.bak: #{$!}\n"
|
puts "Can't copy #{file} to #{file}.bak: #{$!}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
p Time.now
|
||||||
|
p "open & lock file"
|
||||||
begin
|
begin
|
||||||
newsrc = File.new(file, "r+").flock(File::LOCK_EX)
|
newsrc = File.new(file, "r+")
|
||||||
|
newsrc.flock(File::LOCK_EX)
|
||||||
rescue
|
rescue
|
||||||
print "Can't open ${file}: #{$!}\n"
|
puts "Can't open ${file}: #{$!}"
|
||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
|
p Time.now
|
||||||
|
p "opened & locked"
|
||||||
|
|
||||||
# read file
|
# read file
|
||||||
lines = newsrc.readlines
|
lines = newsrc.readlines
|
||||||
|
|
@ -137,23 +166,46 @@ def save_group_as(file, group)
|
||||||
|
|
||||||
# write read stuff & replace group
|
# write read stuff & replace group
|
||||||
lines.each{|line|
|
lines.each{|line|
|
||||||
if line =~ /^#{group}(:|!)/
|
# same parsing as the parse method uses
|
||||||
newsrc.print line
|
unless line =~ /^([^!:]+)([!:])\s(.*)$/x
|
||||||
else
|
puts "Newsrc.parse: Bad newsrc line: #{line}"
|
||||||
|
# restore backup on failure, it'll contain the flaw too, but it'll
|
||||||
|
# be complete
|
||||||
|
if ( ! File.copy("#{file}.bak", file) )
|
||||||
|
puts "Can't copy #{file}.bak to #{file}: #{$!}"
|
||||||
|
end
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
linegroup = $1
|
||||||
|
if linegroup == group["name"]
|
||||||
newsrc.print format(group)
|
newsrc.print format(group)
|
||||||
|
else
|
||||||
|
newsrc.print line
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p Time.now
|
||||||
|
p "truncate, sync, unlock & close file"
|
||||||
|
# sometimes the file grows and then shrinks
|
||||||
|
# this is because a 'read' line van become shorter when more
|
||||||
|
# articles have been read (1,3,5 vs 1-5)
|
||||||
|
# when this happens the file needs to be truncated
|
||||||
|
pos = newsrc.pos
|
||||||
|
newsrc.truncate(pos)
|
||||||
|
newsrc.sync
|
||||||
newsrc.flock(File::LOCK_UN) # what's the right order here?
|
newsrc.flock(File::LOCK_UN) # what's the right order here?
|
||||||
newsrc.close
|
newsrc.close
|
||||||
|
p Time.now
|
||||||
|
p "garbage collect"
|
||||||
|
p Time.now
|
||||||
|
GC.start
|
||||||
|
# }
|
||||||
end
|
end
|
||||||
|
|
||||||
def format(group)
|
def format(group)
|
||||||
name = group["name"]
|
name = group["name"]
|
||||||
sub = group["subscribed"] ? ':' : '!'
|
sub = group["subscribed"] ? ':' : '!'
|
||||||
articles = group["articles"].run_list
|
articles = group["articles"].run_list
|
||||||
#space = articles ? ' ' : ''
|
|
||||||
#return "#{name}#{sub}#{space}#{articles}\n"
|
|
||||||
return "#{name}#{sub} #{articles}\n"
|
return "#{name}#{sub} #{articles}\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -274,7 +326,6 @@ def number(group, offset)
|
||||||
@newsrc["list"].push(upper)
|
@newsrc["list"].push(upper)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def del_group(name)
|
def del_group(name)
|
||||||
if @newsrc["group"].has_key?(name)
|
if @newsrc["group"].has_key?(name)
|
||||||
group = @newsrc["group"][name]
|
group = @newsrc["group"][name]
|
||||||
|
|
@ -306,7 +357,7 @@ def mark(name, article, options = {"where" => ""})
|
||||||
unless @newsrc["group"].has_key?(name)
|
unless @newsrc["group"].has_key?(name)
|
||||||
add_group(name, options)
|
add_group(name, options)
|
||||||
end
|
end
|
||||||
@newsrc["group"][name]["articles"].insert(article)
|
@newsrc["group"][name]["articles"].insert!(article)
|
||||||
end
|
end
|
||||||
|
|
||||||
def mark_list(name, list, options = {"where" => ""})
|
def mark_list(name, list, options = {"where" => ""})
|
||||||
|
|
|
||||||
|
|
@ -737,17 +737,20 @@ def main
|
||||||
|
|
||||||
_create_group_dir(group)
|
_create_group_dir(group)
|
||||||
|
|
||||||
|
subjcount = 0
|
||||||
for subj in @articles.get_group_subjects.sort{|a, b| ward_sort(a, b)}
|
for subj in @articles.get_group_subjects.sort{|a, b| ward_sort(a, b)}
|
||||||
puts "#{subj}" if Debuglevel > 2
|
puts "#{subj}" if Debuglevel > 2
|
||||||
poster = @articles.get_group_poster(subj)
|
poster = @articles.get_group_poster(subj)
|
||||||
# explicitly mark as read
|
# explicitly mark as read
|
||||||
if @config[group].has_key?("-MR") and subj =~ /#{@config[group]["-MR"]}/
|
if @config[group].has_key?("-MR") and subj =~ /#{@config[group]["-MR"]}/
|
||||||
puts "Marking '#{subj}' as read"
|
puts "Marking '#{subj}' as read"
|
||||||
|
subjcount += 1
|
||||||
_mark_read(subj)
|
_mark_read(subj)
|
||||||
# get the juicy bits
|
|
||||||
elsif @config[group].has_key?("-MRF") and poster =~ /#{@config[group]["-MRF"]}/
|
elsif @config[group].has_key?("-MRF") and poster =~ /#{@config[group]["-MRF"]}/
|
||||||
puts "Marking poster '#{poster}' as read (subj: '#{subj}')"
|
puts "Marking poster '#{poster}' as read (subj: '#{subj}')"
|
||||||
|
subjcount += 1
|
||||||
_mark_read(subj)
|
_mark_read(subj)
|
||||||
|
# get the juicy bits
|
||||||
elsif !(@config[group].has_key?("-X") and subj =~ /#{@config[group]["-X"]}/) and
|
elsif !(@config[group].has_key?("-X") and subj =~ /#{@config[group]["-X"]}/) and
|
||||||
subj =~ /#{@config[group]["-I"]}/
|
subj =~ /#{@config[group]["-I"]}/
|
||||||
puts "Match: #{subj}" if Debuglevel > 0
|
puts "Match: #{subj}" if Debuglevel > 0
|
||||||
|
|
@ -757,8 +760,19 @@ def main
|
||||||
puts "Poster match: #{poster}" if Debuglevel > 0
|
puts "Poster match: #{poster}" if Debuglevel > 0
|
||||||
_get_article(subj, group)
|
_get_article(subj, group)
|
||||||
else
|
else
|
||||||
|
subjcount += 1
|
||||||
_mark_remaining(subj, group)
|
_mark_remaining(subj, group)
|
||||||
end
|
end
|
||||||
|
# prevent haveing to start all over in case of a crash
|
||||||
|
# the number of subjects on which to sync should be balanced
|
||||||
|
# between the time it takes to sync and the time it takes to read them
|
||||||
|
# this is just an initial guess
|
||||||
|
# the counter is only used for the mark read stuff, as the get article
|
||||||
|
# stuff saves the newsrc anyway
|
||||||
|
if subjcount >= 150
|
||||||
|
_save_newsrc(group)
|
||||||
|
subjcount = 0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
_wait_for_threads
|
_wait_for_threads
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue