227 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
		
		
			
		
	
	
			227 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| 
								 | 
							
								#!/usr/bin/env ruby
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								=begin
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    Create a cconfig directory based on a xml input.
							 | 
						|||
| 
								 | 
							
								    (C) 2005 by Ren<EFBFBD> Nussbaumer aka KillerFox
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    This script is written for the clinux-System and published
							 | 
						|||
| 
								 | 
							
								    under the terms of GPL 2.0
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    Version: 0.3
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    ChangeLog:
							 | 
						|||
| 
								 | 
							
								        Version 0.3 (Ren<EFBFBD> Nussbaumer):
							 | 
						|||
| 
								 | 
							
								        * Added binary file support
							 | 
						|||
| 
								 | 
							
								        * Added sha1 checksum for binary files
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								        Version 0.2 (Ren<EFBFBD> Nussbaumer):
							 | 
						|||
| 
								 | 
							
								        * Added some commandline options
							 | 
						|||
| 
								 | 
							
								        * Added <EFBFBD>level<EFBFBD> so control the restrictivity of the program
							 | 
						|||
| 
								 | 
							
								        * Added more <EFBFBD>intelligence<EFBFBD> to the program, to detect internal broken dependcies.
							 | 
						|||
| 
								 | 
							
								        * Support <EFBFBD>debug<EFBFBD>-Levels.
							 | 
						|||
| 
								 | 
							
								        * Print statistic at the end of the programs about warnings and errors.
							 | 
						|||
| 
								 | 
							
								        
							 | 
						|||
| 
								 | 
							
								        Version 0.1 (Ren<EFBFBD> Nussbaumer):
							 | 
						|||
| 
								 | 
							
								        * Initial
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    Todo:
							 | 
						|||
| 
								 | 
							
								        * Use an rexml alternative
							 | 
						|||
| 
								 | 
							
								        * Some cleanup
							 | 
						|||
| 
								 | 
							
								        * Optimize
							 | 
						|||
| 
								 | 
							
								        * Testing?
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    Features:
							 | 
						|||
| 
								 | 
							
								        * Create a cconfig directory based on a xml
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								=end
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								require 'rexml/document'
							 | 
						|||
| 
								 | 
							
								require 'getoptlong'
							 | 
						|||
| 
								 | 
							
								require 'base64'
							 | 
						|||
| 
								 | 
							
								require 'digest/sha1'
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								@verbose   = 0
							 | 
						|||
| 
								 | 
							
								@level     = 1
							 | 
						|||
| 
								 | 
							
								@version   = '0.3'
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								@warnings  = 0
							 | 
						|||
| 
								 | 
							
								@errors    = 0
							 | 
						|||
| 
								 | 
							
								@checklist = Array.new
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								def printMsg(prefix, msg)
							 | 
						|||
| 
								 | 
							
								    puts '%-12s %s' % [prefix + ':', msg]
							 | 
						|||
| 
								 | 
							
								end
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								def error(msg, fatal = 0)
							 | 
						|||
| 
								 | 
							
								    @errors += 1
							 | 
						|||
| 
								 | 
							
								    fatal = 0 if(@level < 1)
							 | 
						|||
| 
								 | 
							
								    fatal = 255 if(@level > 1 && !fatal)
							 | 
						|||
| 
								 | 
							
								    printMsg(fatal != 0 ? 'PANIC' : 'ERROR', msg)
							 | 
						|||
| 
								 | 
							
								    Kernel.exit(-fatal) if(fatal != 0)
							 | 
						|||
| 
								 | 
							
								end
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								def warn(msg)
							 | 
						|||
| 
								 | 
							
								    error(msg, 1) if(@level > 1)
							 | 
						|||
| 
								 | 
							
								    @warnings += 1
							 | 
						|||
| 
								 | 
							
								    printMsg('WARNING', msg)
							 | 
						|||
| 
								 | 
							
								end
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								def info(msg)
							 | 
						|||
| 
								 | 
							
								    printMsg('INFO', msg)
							 | 
						|||
| 
								 | 
							
								end
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								def debug(msg, verbosity = 1)
							 | 
						|||
| 
								 | 
							
								    if(@verbose >= verbosity)
							 | 
						|||
| 
								 | 
							
								        printMsg("DEBUG(#{verbosity})", msg)
							 | 
						|||
| 
								 | 
							
								    end
							 | 
						|||
| 
								 | 
							
								end
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								def createObject(name)
							 | 
						|||
| 
								 | 
							
								    error("#{name} already exists.", 1) if(FileTest.exists?(name))
							 | 
						|||
| 
								 | 
							
								    begin
							 | 
						|||
| 
								 | 
							
								        Dir.mkdir(name)
							 | 
						|||
| 
								 | 
							
								    rescue
							 | 
						|||
| 
								 | 
							
								        error("Could not create directory #{name}: #{$!}. Abort.", 7)
							 | 
						|||
| 
								 | 
							
								    end
							 | 
						|||
| 
								 | 
							
								    debug("Object #{File.expand_path(name)} has been created.", 4)
							 | 
						|||
| 
								 | 
							
								end
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								def createAttribute(name, content = nil)
							 | 
						|||
| 
								 | 
							
								    warn("#{name} already exists. Overwrite.") if(FileTest.exists?(name))
							 | 
						|||
| 
								 | 
							
								    begin
							 | 
						|||
| 
								 | 
							
								        file = File.new(name, 'w')
							 | 
						|||
| 
								 | 
							
								        file.print content if(content && !content.empty?)
							 | 
						|||
| 
								 | 
							
								        file.close
							 | 
						|||
| 
								 | 
							
								        debug("Attribute #{File.expand_path(name)} has been created", 4)
							 | 
						|||
| 
								 | 
							
								    rescue
							 | 
						|||
| 
								 | 
							
								        error("Could not create file #{name}: #{$!}. Skipped.")
							 | 
						|||
| 
								 | 
							
								    end
							 | 
						|||
| 
								 | 
							
								end
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								def createLink(name, target, type)
							 | 
						|||
| 
								 | 
							
								    warn("#{name} already exists. Overwrite.") if(FileTest.exists?(name))
							 | 
						|||
| 
								 | 
							
								    error("Broken dependencies! Please take a look if #{target} exists on your system", 2) if(type == 'external' && !FileTest.exists?(target))
							 | 
						|||
| 
								 | 
							
								    if(!FileTest.exists?(target) && type != 'external')
							 | 
						|||
| 
								 | 
							
								        #info("Possible break. But maybe the target #{target} does not yet exists. Checking later.") 
							 | 
						|||
| 
								 | 
							
								        exptarget = File.expand_path(target)
							 | 
						|||
| 
								 | 
							
								        @checklist << exptarget
							 | 
						|||
| 
								 | 
							
								        debug("Adding #{target} to the list of internal dependcies to check.", 2)
							 | 
						|||
| 
								 | 
							
								    end
							 | 
						|||
| 
								 | 
							
								    begin
							 | 
						|||
| 
								 | 
							
								        error('You\'ve a system which does not support symbolic links. Abort.', 3) if(File.symlink(target, name) != 0)
							 | 
						|||
| 
								 | 
							
								    rescue
							 | 
						|||
| 
								 | 
							
								        error("Could not create symlink #{name} => #{target}: #{$!}.", 3)
							 | 
						|||
| 
								 | 
							
								    end
							 | 
						|||
| 
								 | 
							
								    debug("Link #{File.expand_path(name)} has been created", 4)
							 | 
						|||
| 
								 | 
							
								end
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								def doWork(elm)
							 | 
						|||
| 
								 | 
							
								    name = elm.name
							 | 
						|||
| 
								 | 
							
								    attrname = elm.attributes['name']
							 | 
						|||
| 
								 | 
							
								    error("XML Tag with missing name attribute!", 5) if(!attrname)
							 | 
						|||
| 
								 | 
							
								    if(name =~ /(object|cconfig)/)
							 | 
						|||
| 
								 | 
							
								        if(name == 'cconfig')
							 | 
						|||
| 
								 | 
							
								            if(elm.attributes['version'])
							 | 
						|||
| 
								 | 
							
								                info("Found a version string: #{elm.attributes['version']}")
							 | 
						|||
| 
								 | 
							
								                warn("This XML is maybe incompatible with this programm. I'm a version #{@version} script. The XML is generated with a version #{elm.attributes['version']} script. Please update.") if(elm.attributes['version'] > @version)
							 | 
						|||
| 
								 | 
							
								            end
							 | 
						|||
| 
								 | 
							
								        end
							 | 
						|||
| 
								 | 
							
								        createObject(attrname)
							 | 
						|||
| 
								 | 
							
								        if(elm.has_elements?)
							 | 
						|||
| 
								 | 
							
								            pwd = Dir.pwd
							 | 
						|||
| 
								 | 
							
								            Dir.chdir(attrname)
							 | 
						|||
| 
								 | 
							
								            elm.each_element { |e|
							 | 
						|||
| 
								 | 
							
								                doWork(e)
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            Dir.chdir(pwd)
							 | 
						|||
| 
								 | 
							
								        end
							 | 
						|||
| 
								 | 
							
								    elsif(name == 'attribute')
							 | 
						|||
| 
								 | 
							
								        text = nil
							 | 
						|||
| 
								 | 
							
								        e    = nil
							 | 
						|||
| 
								 | 
							
								        text = e.value if((e = elm.get_text))
							 | 
						|||
| 
								 | 
							
								        if(text && elm.attributes['type'] && elm.attributes['type'] == 'binary')
							 | 
						|||
| 
								 | 
							
								            text = Base64.decode64(text)
							 | 
						|||
| 
								 | 
							
								            if(Digest::SHA1.hexdigest(text) != elm.attributes['sha1'])
							 | 
						|||
| 
								 | 
							
								                warn("SHA1 differs from file: #{Dir.pwd}#{attrname}")
							 | 
						|||
| 
								 | 
							
								            end
							 | 
						|||
| 
								 | 
							
								        end
							 | 
						|||
| 
								 | 
							
								        createAttribute(attrname, text)
							 | 
						|||
| 
								 | 
							
								    elsif(name == 'link')
							 | 
						|||
| 
								 | 
							
								        error("link-Tag without content.", 6) if(!elm.has_text?)
							 | 
						|||
| 
								 | 
							
								        error("link with missing target. Skipped.") if(!elm.attributes['target'])
							 | 
						|||
| 
								 | 
							
								        createLink(attrname, elm.get_text.value, elm.attributes['target'])
							 | 
						|||
| 
								 | 
							
								    end
							 | 
						|||
| 
								 | 
							
								end
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								puts "This is #{File.basename(__FILE__)} v#{@version} by Ren<65> Nussbaumer"
							 | 
						|||
| 
								 | 
							
								puts
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								opts = GetoptLong.new(
							 | 
						|||
| 
								 | 
							
								    ['--verbose', '-v', GetoptLong::OPTIONAL_ARGUMENT],
							 | 
						|||
| 
								 | 
							
								    ['--level',   '-l', GetoptLong::REQUIRED_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 '--level'
							 | 
						|||
| 
								 | 
							
								        debug("Setting level to: #{value}", 3)
							 | 
						|||
| 
								 | 
							
								        case value
							 | 
						|||
| 
								 | 
							
								        when 'low'
							 | 
						|||
| 
								 | 
							
								            @level = 0
							 | 
						|||
| 
								 | 
							
								        when 'normal'
							 | 
						|||
| 
								 | 
							
								            @level = 1
							 | 
						|||
| 
								 | 
							
								        when 'paranoid'
							 | 
						|||
| 
								 | 
							
								            @level = 2
							 | 
						|||
| 
								 | 
							
								        else
							 | 
						|||
| 
								 | 
							
								            warn('Unknown level: ' + value)
							 | 
						|||
| 
								 | 
							
								        end
							 | 
						|||
| 
								 | 
							
								    when '--version'
							 | 
						|||
| 
								 | 
							
								        Kernel.exit(0)
							 | 
						|||
| 
								 | 
							
								    else
							 | 
						|||
| 
								 | 
							
								        warn("Unknown option #{arg}#{value && !value.empty? ? ('with value ' + value) : ''}")
							 | 
						|||
| 
								 | 
							
								    end
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								if(!ARGV[0])
							 | 
						|||
| 
								 | 
							
								    puts 'Need at least one argument'
							 | 
						|||
| 
								 | 
							
								    puts "Usage: #{__FILE__} <xml file|->"
							 | 
						|||
| 
								 | 
							
								    Kernel.exit(1)
							 | 
						|||
| 
								 | 
							
								end
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								filedesc = $stdin
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								if(ARGV[0] != '-')
							 | 
						|||
| 
								 | 
							
								    filedesc = File.new(ARGV[0])
							 | 
						|||
| 
								 | 
							
								end
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								doc = REXML::Document.new filedesc
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								doWork(doc.root)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								if(!@checklist.empty?)
							 | 
						|||
| 
								 | 
							
								    info('Now checking all broken internal dependcies again')
							 | 
						|||
| 
								 | 
							
								    broken = 0
							 | 
						|||
| 
								 | 
							
								    @checklist.each { |path|
							 | 
						|||
| 
								 | 
							
								        debug("Checking #{path}.", 2)
							 | 
						|||
| 
								 | 
							
								        if(!FileTest.exists?(path))
							 | 
						|||
| 
								 | 
							
								            broken += 1
							 | 
						|||
| 
								 | 
							
								            warn("Broken dependcies. #{path} does not exist. Please fix.")
							 | 
						|||
| 
								 | 
							
								        end
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    info('Looks good.') if(broken == 0)
							 | 
						|||
| 
								 | 
							
								    info('Bad, bad.')   if(broken > 0)
							 | 
						|||
| 
								 | 
							
								end
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								info("Successed. #{@warnings} warnings, #{@errors} errors")
							 | 
						|||
| 
								 | 
							
								
							 |