225 lines
7.2 KiB
Ruby
225 lines
7.2 KiB
Ruby
|
#!/usr/bin/env ruby
|
|||
|
|
|||
|
require 'misen/style-sgml'
|
|||
|
require 'misen/util'
|
|||
|
|
|||
|
require 'getoptlong'
|
|||
|
require 'fileutils'
|
|||
|
require 'digest/sha1'
|
|||
|
|
|||
|
@version = '0.2'
|
|||
|
@verbose = 0
|
|||
|
@force = false
|
|||
|
@outpath = "#{Dir.pwd}/generated"
|
|||
|
@inpath = "#{Dir.pwd}/source"
|
|||
|
@template = "#{Dir.pwd}/templates"
|
|||
|
@default = 'default.html'
|
|||
|
|
|||
|
@datadir = "#{Dir.pwd}/data"
|
|||
|
@filehash = Hash.new
|
|||
|
|
|||
|
def printMsg(prefix, msg, descriptor = $stdout)
|
|||
|
descriptor.puts '%-12s %s' % [prefix + ':', msg]
|
|||
|
end
|
|||
|
|
|||
|
def panic(msg)
|
|||
|
printMsg('PANIC', msg, $stderr)
|
|||
|
Kernel.exit(-1)
|
|||
|
end
|
|||
|
|
|||
|
def error(msg)
|
|||
|
printMsg('ERROR', msg, $stderr)
|
|||
|
end
|
|||
|
|
|||
|
def warn(msg)
|
|||
|
printMsg('WARNING', msg)
|
|||
|
end
|
|||
|
|
|||
|
def info(msg)
|
|||
|
printMsg('INFO', msg)
|
|||
|
end
|
|||
|
|
|||
|
def debug(msg, verbosity = 1)
|
|||
|
if(@verbose >= verbosity)
|
|||
|
printMsg("DEBUG(#{verbosity})", msg, $stderr)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
def generateMenu(dir, file = nil, level = 0)
|
|||
|
debug("call generateMenu('#{dir}', '#{file}', #{level})")
|
|||
|
template = '<ul<misen:class />>
|
|||
|
<misen:menuentries>
|
|||
|
<li><a href="<misen:url />"<misen:class />><misen:desc /></a><misen:menu /></li>
|
|||
|
</misen:menuentries>
|
|||
|
</ul>'
|
|||
|
|
|||
|
dir = dir + '/' if(!dir.empty? && dir[-1].chr != '/')
|
|||
|
menu = File.new("#{dir}menu.def").readlines
|
|||
|
|
|||
|
data = Hash.new
|
|||
|
menuentries = Array.new
|
|||
|
|
|||
|
menu.each { |x|
|
|||
|
entry = x.split(/\s*\|\s*/, 2)
|
|||
|
e = Hash.new
|
|||
|
e[:class] = (file && dir + entry[0] == file ? ' class="active"' : '')
|
|||
|
if(file && dir + entry[0] == file)
|
|||
|
e[:class] = data[:class] = ' class="active"'
|
|||
|
end
|
|||
|
e[:url] = "/#{dir}#{entry[0]}" # TODO: make relative paths
|
|||
|
e[:desc] = entry[1].strip
|
|||
|
if(FileTest.directory?("#{dir}#{entry[0]}") && FileTest.exists?("#{dir}#{entry[0]}/menu.def"))
|
|||
|
e[:menu] = generateMenu("#{dir}#{entry[0]}", file, level + 1)
|
|||
|
end
|
|||
|
menuentries << e
|
|||
|
}
|
|||
|
|
|||
|
return '' if(menuentries.empty?)
|
|||
|
|
|||
|
data[:menuentries] = menuentries
|
|||
|
|
|||
|
return removeEmptyLine(Misen.expand_text(Misen::STYLE_SGML, template, data))
|
|||
|
|
|||
|
end
|
|||
|
|
|||
|
def generateFiles(dir = '')
|
|||
|
debug("call generateFiles('#{dir}')")
|
|||
|
dir = dir + '/' if(!dir.empty? && dir[-1].chr != '/')
|
|||
|
Dir.foreach(dir.empty? ? '.' : dir) { |x|
|
|||
|
next if(x =~ /^(\.|\.\.)$/)
|
|||
|
|
|||
|
if(x =~ /\.html$/)
|
|||
|
if(!FileTest.exists?(@outpath + '/' + dir + x) || @filehash[dir + x] != Digest::SHA1.hexdigest(File.new(dir + x).read) || @force)
|
|||
|
info("Transforming #{dir}#{x}")
|
|||
|
data = {:style => getStylePath(dir) + 'style.css', :content => File.new("#{dir}#{x}").read, :menu => generateMenu('', dir + File.basename(x, '.html'))}
|
|||
|
Dir.mkdir("#{@outpath}/#{dir}") if(!FileTest.exists?("#{@outpath}/#{dir}"))
|
|||
|
File.open("#{@outpath}/#{dir}#{x}", "w") { |file|
|
|||
|
file.print removeEmptyLine(Misen.expand_text(Misen::STYLE_SGML_EX, @source, data))
|
|||
|
}
|
|||
|
@filehash[dir + x] = Digest::SHA1.hexdigest(File.new(dir + x).read)
|
|||
|
else
|
|||
|
info("Nothing to do for #{dir}#{x}")
|
|||
|
end
|
|||
|
elsif(FileTest.directory?(dir + x))
|
|||
|
begin
|
|||
|
Dir.mkdir("#{@outpath}/#{dir}#{x}") if(!FileTest.exists?("#{@outpath}/#{dir}#{x}"))
|
|||
|
rescue
|
|||
|
panic("Could not create #{@outpath}/#{dir}#{x}: #{$!}")
|
|||
|
end
|
|||
|
generateFiles("#{dir}#{x}")
|
|||
|
elsif(x !~ /(\.def|\.swp)$/)
|
|||
|
if(!FileTest.exists?(@outpath + '/' + dir + x) || @filehash[dir + x] != Digest::SHA1.hexdigest(File.new(dir + x).read) || @force)
|
|||
|
info("Copying file #{dir}#{x}")
|
|||
|
FileUtils.cp(dir + x, @outpath + '/' + dir + x)
|
|||
|
@filehash[dir + x] = Digest::SHA1.hexdigest(File.new(dir + x).read)
|
|||
|
else
|
|||
|
info("No need to copy #{dir}#{x}. Already latest.")
|
|||
|
end
|
|||
|
end
|
|||
|
}
|
|||
|
end
|
|||
|
|
|||
|
def removeEmptyLine(str)
|
|||
|
str.split($/).collect{ |x| x =~ /^\s*$/ ? nil : x}.compact.join($/)
|
|||
|
end
|
|||
|
|
|||
|
def getPath(path)
|
|||
|
return path if(path[0].chr == '/')
|
|||
|
return "#{Dir.pwd}/#{path}"
|
|||
|
end
|
|||
|
|
|||
|
def getStylePath(dir)
|
|||
|
newdir = ''
|
|||
|
|
|||
|
dir.split('/').each {
|
|||
|
newdir += '../'
|
|||
|
}
|
|||
|
|
|||
|
return newdir
|
|||
|
end
|
|||
|
|
|||
|
def usage
|
|||
|
info("Usage: #{File.basename(__FILE__)} [options]")
|
|||
|
info('')
|
|||
|
info('%20s %s' % ['--verbose, -v', 'Verbose output. Add v for more verbose output'])
|
|||
|
info('%20s %s' % ['--inpath, -i', 'Specify where to search for input files [./source]'])
|
|||
|
info('%20s %s' % ['--outpath, -o', 'Specify where to write the output files [./generated]'])
|
|||
|
info('%20s %s' % ['--template, -t', 'Specify where to search for template files [./templates]'])
|
|||
|
info('%20s %s' % ['--default, -d', 'The default template name [default.html]'])
|
|||
|
info('%20s %s' % ['--force, -f', 'Force the new generating of all files [false]'])
|
|||
|
info('%20s %s' % ['--help, -h', 'Print this screen'])
|
|||
|
info('%20s %s' % ['--version, -V', 'Print the version and exit'])
|
|||
|
end
|
|||
|
|
|||
|
puts "This is #{File.basename(__FILE__)} v#{@version} 2005 by Ren<65> Nussbaumer"
|
|||
|
puts
|
|||
|
|
|||
|
opts = GetoptLong.new(
|
|||
|
['--verbose', '-v', GetoptLong::OPTIONAL_ARGUMENT],
|
|||
|
['--inpath', '-i', GetoptLong::REQUIRED_ARGUMENT],
|
|||
|
['--outpath', '-o', GetoptLong::REQUIRED_ARGUMENT],
|
|||
|
['--template', '-t', GetoptLong::REQUIRED_ARGUMENT],
|
|||
|
['--default', '-d', GetoptLong::REQUIRED_ARGUMENT],
|
|||
|
['--force', '-f', GetoptLong::NO_ARGUMENT],
|
|||
|
['--help', '-h', GetoptLong::NO_ARGUMENT],
|
|||
|
['--version', '-V', GetoptLong::NO_ARGUMENT]
|
|||
|
)
|
|||
|
|
|||
|
opts.each { |arg,value|
|
|||
|
case arg
|
|||
|
when '--verbose'
|
|||
|
@verbose += 1
|
|||
|
value.each_byte { |x|
|
|||
|
if(x.chr == 'v')
|
|||
|
@verbose += 1
|
|||
|
end
|
|||
|
}
|
|||
|
debug("Verbosity set to: #{@verbose}")
|
|||
|
when '--inpath'
|
|||
|
@inpath = getPath(value)
|
|||
|
when '--outpath'
|
|||
|
@outpath = getPath(value)
|
|||
|
when '--template'
|
|||
|
@template = getPath(value)
|
|||
|
when '--default'
|
|||
|
@default = value
|
|||
|
when '--force'
|
|||
|
@force = true
|
|||
|
when '--help'
|
|||
|
usage
|
|||
|
Kernel.exit(0)
|
|||
|
when '--version'
|
|||
|
Kernel.exit(0)
|
|||
|
else
|
|||
|
warn("Unknown option #{arg}#{value && !value.empty? ? ('with value ' + value) : ''}")
|
|||
|
end
|
|||
|
}
|
|||
|
|
|||
|
debug("Current configuration:")
|
|||
|
debug('%-10s %s' % ['Inpath:', @inpath])
|
|||
|
debug('%-10s %s' % ['Outpath:', @outpath])
|
|||
|
debug('%-10s %s' % ['Template:', @template])
|
|||
|
debug('%-10s %s' % ['Default:', @default])
|
|||
|
|
|||
|
begin
|
|||
|
Dir.mkdir(@inpath) if(!FileTest.directory?(@inpath))
|
|||
|
Dir.mkdir(@outpath) if(!FileTest.directory?(@outpath))
|
|||
|
Dir.mkdir(@template) if(!FileTest.directory?(@template))
|
|||
|
Dir.mkdir(@datadir) if(!FileTest.directory?(@datadir))
|
|||
|
rescue
|
|||
|
panic("Could not create directory: #{$!}")
|
|||
|
end
|
|||
|
|
|||
|
panic("#{@template}/#{@default} does not exist! Please create at least the default template.") if(!FileTest.exists?("#{@template}/#{@default}"))
|
|||
|
|
|||
|
@source = File.new("#{@template}/#{@default}").read
|
|||
|
|
|||
|
Dir.chdir(@inpath)
|
|||
|
panic("Init directory needs a menu.def!") if(!FileTest.exists?('menu.def'))
|
|||
|
|
|||
|
@filehash = Marshal.load(File.new(@datadir + '/digest').read) if(FileTest.exists?(@datadir + '/digest'))
|
|||
|
generateFiles
|
|||
|
File.open(@datadir + '/digest', 'w') { |file|
|
|||
|
file.print Marshal.dump(@filehash)
|
|||
|
}
|