You can subscribe to this list here.
2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(2) |
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2009 |
Jan
(3) |
Feb
(15) |
Mar
|
Apr
(9) |
May
|
Jun
(6) |
Jul
|
Aug
|
Sep
(23) |
Oct
(25) |
Nov
(44) |
Dec
(9) |
2010 |
Jan
(14) |
Feb
|
Mar
(4) |
Apr
(1) |
May
|
Jun
(3) |
Jul
|
Aug
(4) |
Sep
|
Oct
(10) |
Nov
(4) |
Dec
(22) |
2011 |
Jan
(14) |
Feb
|
Mar
(3) |
Apr
(7) |
May
(16) |
Jun
(4) |
Jul
(6) |
Aug
(3) |
Sep
|
Oct
(4) |
Nov
|
Dec
|
2012 |
Jan
|
Feb
|
Mar
(10) |
Apr
(24) |
May
|
Jun
|
Jul
(2) |
Aug
(2) |
Sep
|
Oct
|
Nov
|
Dec
|
From: <jh...@us...> - 2009-02-06 17:42:51
|
Revision: 73 http://etch.svn.sourceforge.net/etch/?rev=73&view=rev Author: jheiss Date: 2009-02-06 17:42:49 +0000 (Fri, 06 Feb 2009) Log Message: ----------- Delete the links we make to test lchown/lchmod. Tempfile does a "delete if exist" thing on cleanup, so if the link target tempfile gets cleaned up first the link will appear to not exist and not get auto-cleaned. Since we're playing games and turning the file into a link it seems reasonable that we should be responsible for cleanup. Modified Paths: -------------- trunk/client/etch.rb Modified: trunk/client/etch.rb =================================================================== --- trunk/client/etch.rb 2009-02-06 17:42:15 UTC (rev 72) +++ trunk/client/etch.rb 2009-02-06 17:42:49 UTC (rev 73) @@ -680,6 +680,7 @@ rescue Errno::EPERM raise if Process.euid == 0 end + File.delete(lchowntestlink) end if @lchmod_supported.nil? lchmodtestlink = Tempfile.new('etchlchmodtest').path @@ -692,6 +693,7 @@ rescue NotImplementedError @lchmod_supported = false end + File.delete(lchmodtestlink) end set_permissions = false This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2009-02-06 17:42:18
|
Revision: 72 http://etch.svn.sourceforge.net/etch/?rev=72&view=rev Author: jheiss Date: 2009-02-06 17:42:15 +0000 (Fri, 06 Feb 2009) Log Message: ----------- Replace REXML for XML parsing with LibXML. Should be faster (or rather use less CPU, which is more important in our case as it improves scalability), and adds support for DTD validation. Modified Paths: -------------- trunk/server/lib/etchserver.rb Modified: trunk/server/lib/etchserver.rb =================================================================== --- trunk/server/lib/etchserver.rb 2009-02-06 17:41:09 UTC (rev 71) +++ trunk/server/lib/etchserver.rb 2009-02-06 17:42:15 UTC (rev 72) @@ -3,7 +3,7 @@ require 'digest/sha1' # hexdigest require 'base64' # decode64, encode64 require 'fileutils' # mkdir_p -require 'rexml/document' +require 'libxml' require 'erb' require 'versiontype' # Version @@ -85,28 +85,34 @@ # base directory. @sourcebase = "#{@tagbase}/source" @sitelibbase = "#{@tagbase}/sitelibs" + @config_dtd_file = "#{@tagbase}/config.dtd" @defaults_file = "#{@tagbase}/defaults.xml" @nodes_file = "#{@tagbase}/nodes.xml" @nodegroups_file = "#{@tagbase}/nodegroups.xml" @origbase = "#{@configbase}/orig" # + # Load the DTD which is used to validate config.xml files + # + @config_dtd = LibXML::XML::Dtd.new(IO.read(@config_dtd_file)) + + # # Load the defaults.xml file which sets defaults for parameters that the # user doesn't specify in his config.xml files. # - - @defaults_xml = REXML::Document.new(File.open(@defaults_file)) - + + @defaults_xml = LibXML::XML::Document.file(@defaults_file) + # # Load the nodes file # - @nodes_xml = REXML::Document.new(File.open(@nodes_file)) + @nodes_xml = LibXML::XML::Document.file(@nodes_file) # Extract the groups for this node - thisnodeelem = @nodes_xml.root.elements["/nodes/node[@name='#{@fqdn}']"] + thisnodeelem = @nodes_xml.find_first("/nodes/node[@name='#{@fqdn}']") groupshash = {} if thisnodeelem - thisnodeelem.elements.each('group') { |group| groupshash[group.text] = true } + thisnodeelem.find('group').each { |group| groupshash[group.content] = true } else RAILS_DEFAULT_LOGGER.info "No entry found for node #{@fqdn} in nodes.xml" if (@debug) # Some folks might want to terminate here @@ -118,14 +124,14 @@ # Load the node groups file # - @nodegroups_xml = REXML::Document.new(File.open(@nodegroups_file)) + @nodegroups_xml = LibXML::XML::Document.file(@nodegroups_file) # Extract the node group hierarchy into a hash for easy reference @group_hierarchy = {} - @nodegroups_xml.root.elements.each('/nodegroups/nodegroup') do |parent| - parent.elements.each('child') do |child| - @group_hierarchy[child.text] = [] if !@group_hierarchy[child.text] - @group_hierarchy[child.text] << parent.attributes['name'] + @nodegroups_xml.find('/nodegroups/nodegroup').each do |parent| + parent.find('child').each do |child| + @group_hierarchy[child.content] = [] if !@group_hierarchy[child.content] + @group_hierarchy[child.content] << parent.attributes['name'] end end @@ -232,9 +238,10 @@ end # Generate the XML document to return to the client - response_xml = REXML::Document.new '<files></files>' + response_xml = LibXML::XML::Document.new + response_xml.root = LibXML::XML::Node.new('files') # Add configs for files we generated - configs_xml = REXML::Element.new 'configs' + configs_xml = LibXML::XML::Node.new('configs') @configs.each do |file, config_xml| # Update the stored record of the config # Exclude configs which correspond to files for which we're @@ -248,30 +255,30 @@ end end # And add the config to the response to return to the client - configs_xml.add_element config_xml.root + configs_xml << config_xml.root.copy(true) end - response_xml.root.add_element configs_xml + response_xml.root << configs_xml # Add the files for which we need sums - need_sums_xml = REXML::Element.new 'need_sums' + need_sums_xml = LibXML::XML::Node.new('need_sums') @need_sum.each_key do |need| - need_xml = REXML::Element.new 'need_sum' - need_xml.text = need - need_sums_xml.add_element need_xml + need_xml = LibXML::XML::Node.new('need_sum') + need_xml.content = need + need_sums_xml << need_xml end - response_xml.root.add_element need_sums_xml + response_xml.root << need_sums_xml # Add the files for which we need originals - need_origs_xml = REXML::Element.new 'need_origs' + need_origs_xml = LibXML::XML::Node.new('need_origs') @need_orig.each_key do |need| - need_xml = REXML::Element.new 'need_orig' - need_xml.text = need - need_origs_xml.add_element need_xml + need_xml = LibXML::XML::Node.new('need_orig') + need_xml.content = need + need_origs_xml << need_xml end - response_xml.root.add_element need_origs_xml + response_xml.root << need_origs_xml # FIXME: clean up XML formatting # But only if we're in debug mode, in regular mode nobody but the # machines will see the XML and they don't care if it is pretty. - # Tidy's formatting breaks things, it inserts leading/trailing whitespace into text elements + # Tidy's formatting breaks things, it inserts leading/trailing whitespace into text nodes if @debug && false require 'tidy' Tidy.path = '/sw/lib/libtidy.dylib' @@ -325,30 +332,26 @@ raise "Circular dependency detected for #{file}" end @filestack[file] = true - + # Load the config.xml file - begin - config_xml = REXML::Document.new(File.open("#{@sourcebase}/#{file}/config.xml")) - rescue => e - # Help the user figure out where the exception occurred, REXML doesn't - # include the filename when it throws a parse exception. - raise e.exception("Exception while processing config.xml for file #{file}:\n" + e.message) - end - + config_xml = LibXML::XML::Document.file(File.join(@sourcebase, file, 'config.xml')) + # Filter the config.xml file by looking for attributes configfilter!(config_xml.root) - - # REXML doesn't support validation, otherwise we'd validate - # the filtered file against config.dtd here - + + # Validate the filtered file against config.dtd + if !config_xml.validate(@config_dtd) + raise "Filtered config.xml for #{file} fails validation" + end + done = false # Generate any other files that this file depends on depends = [] - config_xml.root.elements.each('/config/depend') do |depend| - RAILS_DEFAULT_LOGGER.info "Generating dependency #{depend.text}" if (@debug) - depends << depend.text - generate_file(depend.text, files) + config_xml.find('/config/depend').each do |depend| + RAILS_DEFAULT_LOGGER.info "Generating dependency #{depend.content}" if (@debug) + depends << depend.content + generate_file(depend.content, files) end # If any dependency failed to generate (due to a need for orig sum or # contents from the client) then we need to unroll the whole dependency @@ -384,20 +387,20 @@ # Check to see if the user has requested that we revert back to the # original file. - if config_xml.root.elements['/config/revert'] && !done + if config_xml.find_first('/config/revert') && !done # Pass the revert action back to the client filter_xml!(config_xml, ['revert']) done = true end # Perform any server setup commands - if config_xml.root.elements['/config/server_setup'] && !done + if config_xml.find_first('/config/server_setup') && !done RAILS_DEFAULT_LOGGER.info "Processing server setup commands" if (@debug) - config_xml.root.elements.each('/config/server_setup/exec') do |cmd| - RAILS_DEFAULT_LOGGER.info " Executing #{cmd.text}" if (@debug) - success = system(cmd.text) + config_xml.find('/config/server_setup/exec').each do |cmd| + RAILS_DEFAULT_LOGGER.info " Executing #{cmd.content}" if (@debug) + success = system(cmd.content) if !success - raise "Server setup command #{cmd.text} for file #{file} exited with non-zero value" + raise "Server setup command #{cmd.content} for file #{file} exited with non-zero value" end end end @@ -435,43 +438,42 @@ # Regular file # - if config_xml.root.elements['/config/file'] && !done + if config_xml.find_first('/config/file') && !done # # Assemble the contents for the file # newcontents = '' - if config_xml.root.elements['/config/file/source/plain'] - plain_elements = config_xml.root.elements.to_a('/config/file/source/plain') + if config_xml.find_first('/config/file/source/plain') + plain_elements = config_xml.find('/config/file/source/plain').to_a if check_for_inconsistency(plain_elements) raise "Inconsistent 'plain' entries for #{file}" end # Just slurp the file in - plain_file = config_xml.root.elements['/config/file/source/plain'].text + plain_file = plain_elements.first.content newcontents = IO::read(plain_file) - - elsif config_xml.root.elements['/config/file/source/template'] - template_elements = config_xml.root.elements.to_a('/config/file/source/template') + elsif config_xml.find_first('/config/file/source/template') + template_elements = config_xml.find('/config/file/source/template').to_a if check_for_inconsistency(template_elements) raise "Inconsistent 'template' entries for #{file}" end # Run the template through ERB to generate the file contents - template = config_xml.root.elements['/config/file/source/template'].text + template = template_elements.first.content external = EtchExternalSource.new(file, original_file, @facts, @groups, @sourcebase, @sitelibbase, @debug) newcontents = external.process_template(template) - elsif config_xml.root.elements['/config/file/source/script'] - script_elements = config_xml.root.elements.to_a('/config/file/source/script') + elsif config_xml.find_first('/config/file/source/script') + script_elements = config_xml.find('/config/file/source/script').to_a if check_for_inconsistency(script_elements) raise "Inconsistent 'script' entries for #{file}" end # Run the script to generate the file contents - script = config_xml.root.elements['/config/file/source/script'].text + script = script_elements.first.content external = EtchExternalSource.new(file, original_file, @facts, @groups, @sourcebase, @sitelibbase, @debug) newcontents = external.run_script(script) - elsif config_xml.root.elements['/config/file/always_manage_metadata'] + elsif config_xml.find_first('/config/file/always_manage_metadata') # always_manage_metadata is a special case where we proceed # even if we don't have any source for file contents. else @@ -490,8 +492,8 @@ # keep empty files or always manage the metadata, then assume # this file is not applicable to this node and do nothing. if newcontents == '' && - ! config_xml.root.elements['/config/file/allow_empty'] && - ! config_xml.root.elements['/config/file/always_manage_metadata'] + ! config_xml.find_first('/config/file/allow_empty') && + ! config_xml.find_first('/config/file/always_manage_metadata') RAILS_DEFAULT_LOGGER.info "New contents for file #{file} empty, doing nothing" if (@debug) else # Finish assembling the file contents as long as we're not @@ -499,34 +501,38 @@ # proceeding based only on always_manage_metadata we want to make # sure that the only action we'll take is to manage metadata, not # muck with the file's contents. - if !(newcontents == '' && config_xml.elements['/config/file/always_manage_metadata']) + if !(newcontents == '' && config_xml.find_first('/config/file/always_manage_metadata')) # Add the warning message (if defined) warning_file = nil - if config_xml.root.elements['/config/file/warning_file'] - warning_file = config_xml.root.elements['/config/file/warning_file'].text - elsif @defaults_xml.root.elements['/config/file/warning_file'] - warning_file = @defaults_xml.root.elements['/config/file/warning_file'].text + if config_xml.find_first('/config/file/warning_file') + if !config_xml.find_first('/config/file/warning_file').content.empty? + warning_file = config_xml.find_first('/config/file/warning_file').content + end + elsif @defaults_xml.find_first('/config/file/warning_file') + if !@defaults_xml.find_first('/config/file/warning_file').content.empty? + warning_file = @defaults_xml.find_first('/config/file/warning_file').content + end end if warning_file - message = '' + warning = '' # First the comment opener - comment_open = '' - if config_xml.root.elements['/config/file/comment_open'] - comment_open = config_xml.root.elements['/config/file/comment_open'].text - elsif @defaults_xml.root.elements['/config/file/comment_open'] - comment_open = @defaults_xml.root.elements['/config/file/comment_open'].text + comment_open = nil + if config_xml.find_first('/config/file/comment_open') + comment_open = config_xml.find_first('/config/file/comment_open').content + elsif @defaults_xml.find_first('/config/file/comment_open') + comment_open = @defaults_xml.find_first('/config/file/comment_open').content end - if comment_open - message << comment_open << "\n" + if comment_open && !comment_open.empty? + warning << comment_open << "\n" end # Then the message comment_line = '# ' - if config_xml.root.elements['/config/file/comment_line'] - comment_line = config_xml.root.elements['/config/file/comment_line'].text - elsif @defaults_xml.root.elements['/config/file/comment_line'] - comment_line = @defaults_xml.root.elements['/config/file/comment_line'].text + if config_xml.find_first('/config/file/comment_line') + comment_line = config_xml.find_first('/config/file/comment_line').content + elsif @defaults_xml.find_first('/config/file/comment_line') + comment_line = @defaults_xml.find_first('/config/file/comment_line').content end warnpath = Pathname.new(warning_file) @@ -536,19 +542,19 @@ File.open(warning_file) do |warnfile| while line = warnfile.gets - message << comment_line << line + warning << comment_line << line end end # And last the comment closer - comment_close = '' - if config_xml.root.elements['/config/file/comment_close'] - comment_close = config_xml.root.elements['/config/file/comment_close'].text - elsif @defaults_xml.root.elements['/config/file/comment_close'] - comment_close = @defaults_xml.root.elements['/config/file/comment_close'].text + comment_close = nil + if config_xml.find_first('/config/file/comment_close') + comment_close = config_xml.find_first('/config/file/comment_close').content + elsif @defaults_xml.find_first('/config/file/comment_close') + comment_close = @defaults_xml.find_first('/config/file/comment_close').content end - if comment_close - message << comment_close << "\n" + if comment_close && !comment_close.empty? + warning << comment_close << "\n" end # By default we insert the warning at the top of the @@ -556,67 +562,65 @@ # scripts) have a special first line. The user can flag # those files to have the warning inserted starting at the # second line. - if !config_xml.root.elements['/config/file/warning_on_second_line'] + if !config_xml.find_first('/config/file/warning_on_second_line') # And then other files (notably Solaris crontabs) can't # have any blank lines. Normally we insert a blank # line between the warning message and the generated # file to improve readability. The user can flag us to # not insert that blank line. - if !config_xml.root.elements['/config/file/no_space_around_warning'] - newcontents = message + "\n" + newcontents + if !config_xml.find_first('/config/file/no_space_around_warning') + newcontents = warning + "\n" + newcontents else - newcontents = message + newcontents + newcontents = warning + newcontents end else parts = newcontents.split("\n", 2) - if !config_xml.root.elements['/config/file/no_space_around_warning'] - newcontents = parts[0] << "\n\n" << message << "\n" << parts[1] + if !config_xml.find_first('/config/file/no_space_around_warning') + newcontents = parts[0] << "\n\n" << warning << "\n" << parts[1] else - newcontents = parts[0] << message << parts[1] + newcontents = parts[0] << warning << parts[1] end end end # if warning_file # Add the generated file contents to the XML - contentselem = REXML::Element.new 'contents' - contentselem.text = Base64.encode64(newcontents) - config_xml.root.elements['/config/file'].add_element contentselem + contentselem = LibXML::XML::Node.new('contents') + contentselem.content = Base64.encode64(newcontents) + config_xml.find_first('/config/file') << contentselem end # Remove the source configuration from the XML, the # client won't need to see it - config_xml.root.delete_element '/config/file/source' + config_xml.find('/config/file/source').each { |elem| elem.remove! } # Remove all of the warning related elements from the XML, the # client won't need to see them - config_xml.root.delete_element '/config/file/warning_file' - config_xml.root.delete_element '/config/file/warning_on_second_line' - config_xml.root.delete_element '/config/file/no_space_around_warning' - config_xml.root.delete_element '/config/file/comment_open' - config_xml.root.delete_element '/config/file/comment_line' - config_xml.root.delete_element '/config/file/comment_close' - config_xml.root.delete_element '/config/file/warning_file' - config_xml.root.delete_element '/config/file/warning_file' - + config_xml.find('/config/file/warning_file').each { |elem| elem.remove! } + config_xml.find('/config/file/warning_on_second_line').each { |elem| elem.remove! } + config_xml.find('/config/file/no_space_around_warning').each { |elem| elem.remove! } + config_xml.find('/config/file/comment_open').each { |elem| elem.remove! } + config_xml.find('/config/file/comment_line').each { |elem| elem.remove! } + config_xml.find('/config/file/comment_close').each { |elem| elem.remove! } + # If the XML doesn't contain ownership and permissions entries # then add appropriate ones based on the defaults - if !config_xml.root.elements['/config/file/owner'] - if @defaults_xml.root.elements['/config/file/owner'] - config_xml.root.elements['/config/file'].add_element(@defaults_xml.root.elements['/config/file/owner'].dup) + if !config_xml.find_first('/config/file/owner') + if @defaults_xml.find_first('/config/file/owner') + config_xml.find_first('/config/file') << @defaults_xml.find_first('/config/file/owner').copy(true) else raise "defaults.xml needs /config/file/owner" end end - if !config_xml.root.elements['/config/file/group'] - if @defaults_xml.root.elements['/config/file/group'] - config_xml.root.elements['/config/file'].add_element(@defaults_xml.root.elements['/config/file/group'].dup) + if !config_xml.find_first('/config/file/group') + if @defaults_xml.find_first('/config/file/group') + config_xml.find_first('/config/file') << @defaults_xml.find_first('/config/file/group').copy(true) else raise "defaults.xml needs /config/file/group" end end - if !config_xml.root.elements['/config/file/perms'] - if @defaults_xml.root.elements['/config/file/perms'] - config_xml.root.elements['/config/file'].add_element(@defaults_xml.root.elements['/config/file/perms'].dup) + if !config_xml.find_first('/config/file/perms') + if @defaults_xml.find_first('/config/file/perms') + config_xml.find_first('/config/file') << @defaults_xml.find_first('/config/file/perms').copy(true) else raise "defaults.xml needs /config/file/perms" end @@ -633,33 +637,33 @@ # Symbolic link # - if config_xml.root.elements['/config/link'] && !done + if config_xml.find_first('/config/link') && !done dest = nil - if config_xml.root.elements['/config/link/dest'] - dest_elements = config_xml.root.elements.to_a('/config/link/dest') + if config_xml.find_first('/config/link/dest') + dest_elements = config_xml.find('/config/link/dest').to_a if check_for_inconsistency(dest_elements) raise "Inconsistent 'dest' entries for #{file}" end - dest = config_xml.root.elements['/config/link/dest'].text - elsif config_xml.root.elements['/config/link/script'] + dest = dest_elements.first.content + elsif config_xml.find_first('/config/link/script') # The user can specify a script to perform more complex # testing to decide whether to create the link or not and # what its destination should be. - script_elements = config_xml.root.elements.to_a('/config/link/script') + script_elements = config_xml.find('/config/link/script').to_a if check_for_inconsistency(script_elements) raise "Inconsistent 'script' entries for #{file}" end - script = config_xml.root.elements['/config/link/script'].text + script = script_elements.first.content external = EtchExternalSource.new(file, original_file, @facts, @groups, @sourcebase, @sitelibbase, @debug) dest = external.run_script(script) - # Remove the script element from the XML, the client won't need - # to see it - config_xml.root.delete_element '/config/link/script' + # Remove the script element(s) from the XML, the client won't need + # to see them + script_elements.each { |se| se.remove! } else # If the filtering has removed the destination for the link, # that means it doesn't apply to this node. @@ -671,31 +675,31 @@ else # If there isn't a dest element in the XML (if the user used a # script) then insert one for the benefit of the client - if !config_xml.root.elements['/config/link/dest'] - destelem = REXML::Element.new 'dest' - destelem.text = dest - config_xml.root.elements['/config/link'].add_element destelem + if !config_xml.find_first('/config/link/dest') + destelem = LibXML::XML::Node.new('dest') + destelem.content = dest + config_xml.find_first('/config/link') << destelem end # If the XML doesn't contain ownership and permissions entries # then add appropriate ones based on the defaults - if !config_xml.root.elements['/config/link/owner'] - if @defaults_xml.root.elements['/config/link/owner'] - config_xml.root.elements['/config/link'].add_element(@defaults_xml.root.elements['/config/link/owner'].dup) + if !config_xml.find_first('/config/link/owner') + if @defaults_xml.find_first('/config/link/owner') + config_xml.find_first('/config/link') << @defaults_xml.find_first('/config/link/owner').copy(true) else raise "defaults.xml needs /config/link/owner" end end - if !config_xml.root.elements['/config/link/group'] - if @defaults_xml.root.elements['/config/link/group'] - config_xml.root.elements['/config/link'].add_element(@defaults_xml.root.elements['/config/link/group'].dup) + if !config_xml.find_first('/config/link/group') + if @defaults_xml.find_first('/config/link/group') + config_xml.find_first('/config/link') << @defaults_xml.find_first('/config/link/group').copy(true) else raise "defaults.xml needs /config/link/group" end end - if !config_xml.root.elements['/config/link/perms'] - if @defaults_xml.root.elements['/config/link/perms'] - config_xml.root.elements['/config/link'].add_element(@defaults_xml.root.elements['/config/link/perms'].dup) + if !config_xml.find_first('/config/link/perms') + if @defaults_xml.find_first('/config/link/perms') + config_xml.find_first('/config/link') << @defaults_xml.find_first('/config/link/perms').copy(true) else raise "defaults.xml needs /config/link/perms" end @@ -712,26 +716,26 @@ # Directory # - if config_xml.root.elements['/config/directory'] && !done + if config_xml.find_first('/config/directory') && !done create = false - if config_xml.root.elements['/config/directory/create'] + if config_xml.find_first('/config/directory/create') create = true - elsif config_xml.root.elements['/config/directory/script'] + elsif config_xml.find_first('/config/directory/script') # The user can specify a script to perform more complex testing # to decide whether to create the directory or not. - script_elements = config_xml.root.elements.to_a('/config/directory/script') + script_elements = config_xml.find('/config/directory/script').to_a if check_for_inconsistency(script_elements) raise "Inconsistent 'script' entries for #{file}" end - script = config_xml.root.elements['/config/directory/script'].text + script = script_elements.first.content external = EtchExternalSource.new(file, original_file, @facts, @groups, @sourcebase, @sitelibbase, @debug) create = external.run_script(script) create = false if create.empty? - # Remove the script element from the XML, the client won't need - # to see it - config_xml.root.delete_element '/config/directory/script' + # Remove the script element(s) from the XML, the client won't need + # to see them + script_elements.each { |se| se.remove! } else # If the filtering has removed the directive to create this # directory, that means it doesn't apply to this node. @@ -743,30 +747,30 @@ else # If there isn't a create element in the XML (if the user used a # script) then insert one for the benefit of the client - if !config_xml.root.elements['/config/directory/create'] - createelem = REXML::Element.new 'create' - config_xml.root.elements['/config/directory'].add_element createelem + if !config_xml.find_first('/config/directory/create') + createelem = LibXML::XML::Node.new('create') + config_xml.find_first('/config/directory') << createelem end # If the XML doesn't contain ownership and permissions entries # then add appropriate ones based on the defaults - if !config_xml.root.elements['/config/directory/owner'] - if @defaults_xml.root.elements['/config/directory/owner'] - config_xml.root.elements['/config/directory'].add_element(@defaults_xml.root.elements['/config/directory/owner'].dup) + if !config_xml.find_first('/config/directory/owner') + if @defaults_xml.find_first('/config/directory/owner') + config_xml.find_first('/config/directory') << @defaults_xml.find_first('/config/directory/owner').copy(true) else raise "defaults.xml needs /config/directory/owner" end end - if !config_xml.root.elements['/config/directory/group'] - if @defaults_xml.root.elements['/config/directory/group'] - config_xml.root.elements['/config/directory'].add_element(@defaults_xml.root.elements['/config/directory/group'].dup) + if !config_xml.find_first('/config/directory/group') + if @defaults_xml.find_first('/config/directory/group') + config_xml.find_first('/config/directory') << @defaults_xml.find_first('/config/directory/group').copy(true) else raise "defaults.xml needs /config/directory/group" end end - if !config_xml.root.elements['/config/directory/perms'] - if @defaults_xml.root.elements['/config/directory/perms'] - config_xml.root.elements['/config/directory'].add_element(@defaults_xml.root.elements['/config/directory/perms'].dup) + if !config_xml.find_first('/config/directory/perms') + if @defaults_xml.find_first('/config/directory/perms') + config_xml.find_first('/config/directory') << @defaults_xml.find_first('/config/directory/perms').copy(true) else raise "defaults.xml needs /config/directory/perms" end @@ -783,26 +787,26 @@ # Delete whatever is there # - if config_xml.root.elements['/config/delete'] && !done + if config_xml.find_first('/config/delete') && !done proceed = false - if config_xml.root.elements['/config/delete/proceed'] + if config_xml.find_first('/config/delete/proceed') proceed = true - elsif config_xml.root.elements['/config/delete/script'] + elsif config_xml.find_first('/config/delete/script') # The user can specify a script to perform more complex testing # to decide whether to delete the file or not. - script_elements = config_xml.root.elements.to_a('/config/delete/script') + script_elements = config_xml.find('/config/delete/script').to_a if check_for_inconsistency(script_elements) raise "Inconsistent 'script' entries for #{file}" end - script = config_xml.root.elements['/config/delete/script'].text + script = script_elements.first.content external = EtchExternalSource.new(file, original_file, @facts, @groups, @sourcebase, @sitelibbase, @debug) proceed = external.run_script(script) proceed = false if proceed.empty? - # Remove the script element from the XML, the client won't need - # to see it - config_xml.root.delete_element '/config/delete/script' + # Remove the script element(s) from the XML, the client won't need + # to see them + script_elements.each { |se| se.remove! } else # If the filtering has removed the directive to remove this # file, that means it doesn't apply to this node. @@ -814,9 +818,9 @@ else # If there isn't a proceed element in the XML (if the user used a # script) then insert one for the benefit of the client - if !config_xml.root.elements['/config/delete/proceed'] - proceedelem = REXML::Element.new 'proceed' - config_xml.root.elements['/config/delete'].add_element proceedelem + if !config_xml.find_first('/config/delete/proceed') + proceedelem = LibXML::XML::Node.new('proceed') + config_xml.find_first('/config/delete') << proceedelem end # Send the file contents and metadata to the client @@ -826,10 +830,10 @@ end end - if done && !config_xml.root.elements.empty? + if done && config_xml.find_first('/config/*') # The client needs this attribute to know to which file # this chunk of XML refers - config_xml.root.add_attribute('filename', file) + config_xml.root.attributes['filename'] = file @configs[file] = config_xml end @@ -840,11 +844,18 @@ ALWAYS_KEEP = ['depend', 'setup', 'pre', 'test_before_post', 'post', 'test'] def filter_xml_completely!(config_xml, keepers=[]) - config_xml.root.elements.each do |elem| + remove = [] + config_xml.root.each_element do |elem| if !keepers.include?(elem.name) - config_xml.root.elements.delete(elem) + # remove! throws off each_element, have to save up a list of + # elements to remove and remove them outside of the each_element + # block + # http://rubyforge.org/tracker/index.php?func=detail&aid=23799&group_id=494&atid=1971 + #elem.remove! + remove << elem end end + remove.each { |elem| elem.remove! } # FIXME: strip comments (tidy is doing this now...) end def filter_xml!(config_xml, keepers=[]) @@ -852,23 +863,32 @@ end def configfilter!(element) - element.elements.each do |child| - child.attributes.each_attribute do |attr| - if !check_attribute(attr.name, attr.value) - element.delete_element(child) - # FIXME: - # Ideally we'd jump to the next element here, looks like that - # would require a catch/throw block. I think it will work - # anyway, just possibly spend some useless time evaluating - # additional attributes. - else - child.attributes.delete(attr) + elem_remove = [] + attr_remove = [] + element.each_element do |elem| + catch :next_element do + elem.attributes.each do |attribute| + if !check_attribute(attribute.name, attribute.value) + # Node#remove! throws off Node#each_element, so we have to save + # up a list of elements to remove and remove them outside of + # the each_element block + # http://rubyforge.org/tracker/index.php?func=detail&aid=23799&group_id=494&atid=1971 + #elem.remove! + elem_remove << elem + throw :next_element + else + # Same deal with Attr#remove! and Attributes#each + # http://rubyforge.org/tracker/index.php?func=detail&aid=23829&group_id=494&atid=1971 + #attribute.remove! + attr_remove << attribute + end end + # Then check any children of this element + configfilter!(elem) end - - # Then check any children of this element - configfilter!(child) end + elem_remove.each { |elem| elem.remove! } + attr_remove.each { |attribute| attribute.remove! } end # Used when parsing each config.xml to filter out any elements which @@ -954,7 +974,7 @@ # This subroutine checks a list of XML elements to determine if they all # contain the same value. Returns true if there is inconsistency. def check_for_inconsistency(elements) - elements_as_text = elements.collect { |elem| elem.text } + elements_as_text = elements.collect { |elem| elem.content } if elements_as_text.uniq.length != 1 return true else This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2009-02-06 17:41:12
|
Revision: 71 http://etch.svn.sourceforge.net/etch/?rev=71&view=rev Author: jheiss Date: 2009-02-06 17:41:09 +0000 (Fri, 06 Feb 2009) Log Message: ----------- Add a comment about the will_paginate config.gem entry Modified Paths: -------------- trunk/server/config/environment.rb Modified: trunk/server/config/environment.rb =================================================================== --- trunk/server/config/environment.rb 2009-02-06 17:40:11 UTC (rev 70) +++ trunk/server/config/environment.rb 2009-02-06 17:41:09 UTC (rev 71) @@ -25,6 +25,10 @@ # config.gem "bj" # config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net" # config.gem "aws-s3", :lib => "aws/s3" + # This is the syntax in the will_paginate docs, but seems to trigger + # an install of exactly 2.3.6. At this point I don't know of any + # specific version requirement we have, so I'm just letting it install + # the latest. #config.gem 'mislav-will_paginate', :version => '~> 2.3.6', :lib => 'will_paginate', :source => 'http://gems.github.com' config.gem 'mislav-will_paginate', :lib => 'will_paginate', :source => 'http://gems.github.com' This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2009-02-06 17:40:13
|
Revision: 70 http://etch.svn.sourceforge.net/etch/?rev=70&view=rev Author: jheiss Date: 2009-02-06 17:40:11 +0000 (Fri, 06 Feb 2009) Log Message: ----------- Move the code to compute the counts of nodes in various states from the dashboard view to the controller to be a little more MVC compliant. Add a couple of cute flash charts to the dashboard. Modified Paths: -------------- trunk/server/app/controllers/dashboard_controller.rb trunk/server/app/views/dashboard/index.html.erb Modified: trunk/server/app/controllers/dashboard_controller.rb =================================================================== --- trunk/server/app/controllers/dashboard_controller.rb 2009-02-06 17:39:44 UTC (rev 69) +++ trunk/server/app/controllers/dashboard_controller.rb 2009-02-06 17:40:11 UTC (rev 70) @@ -1,4 +1,110 @@ class DashboardController < ApplicationController def index + @total_count = Client.count + @healthy_count = Client.count(:conditions => ["status = 0 AND updated_at > ?", 24.hours.ago]) + @broken_count = Client.count(:conditions => ["status != 0 AND status != 200 AND updated_at > ?", 24.hours.ago]) + @disabled_count = Client.count(:conditions => ["status = 200 AND updated_at > ?", 24.hours.ago]) + @stale_count = Client.count(:conditions => ["updated_at <= ?", 24.hours.ago]) + + respond_to do |format| + format.html { + @status_graph = open_flash_chart_object(300, 300, url_for( :action => 'index', :graph => 'status', :format => :json )) + @client_graph = open_flash_chart_object(500, 300, url_for( :action => 'index', :graph => 'client', :format => :json )) + } + format.json { + case params[:graph] + when 'status' + pie = Pie.new + pie.start_angle = 0 + pie.animate = true + pie.tooltip = '#label# of #total#' + pie.colours = ['#36E728', '#D01F1F', '#E9F11D', '#741FD0'] + pie.values = [PieValue.new(@healthy_count, @healthy_count == 0 ? '' : "Healthy: #{@healthy_count}"), + PieValue.new(@broken_count, @broken_count == 0 ? '' : "Broken: #{@broken_count}"), + PieValue.new(@disabled_count, @disabled_count == 0 ? '' : "Disabled: #{@disabled_count}"), + PieValue.new(@stale_count, @stale_count == 0 ? '' : "Stale: #{@stale_count}")] + + title = Title.new("Client Status") + + chart = OpenFlashChart.new + chart.title = title + chart.add_element(pie) + chart.bg_colour = '#FFFFFF' + + chart.x_axis = nil + + render :text => chart, :layout => false + when 'client' + clients = [] + months = [] + # Find the oldest client + oldest = Client.find(:first, :order => 'created_at') + # Get the month and year of that date + month = oldest.created_at.mon + year = oldest.created_at.year + # Iterate months to present + (year..Time.now.year).each do |y| + start_month = 1 + end_month = 12 + if y == year + start_month = month + end + if y == Time.now.year + end_month = Time.now.month + end + (start_month..end_month).each do |m| + end_time = nil + if m == 12 + end_time = Time.local(y+1, 1) + else + end_time = Time.local(y, m+1) + end + # This should get us the last second of the desired month + end_time - 1 + clients << Client.count(:conditions => ["created_at <= ?", end_time]) + months << end_time.strftime('%b %Y') + end + end + + line_dot = LineDot.new + line_dot.text = "Clients" + line_dot.width = 1 + line_dot.colour = '#6363AC' + line_dot.dot_size = 5 + line_dot.values = clients + + tmp = [] + x_labels = XAxisLabels.new + x_labels.set_vertical() + months.each do |text| + tmp << XAxisLabel.new(text, '#0000ff', 12, 'diagonal') + end + x_labels.labels = tmp + x = XAxis.new + x.set_labels(x_labels) + + y = YAxis.new + # Set the top of the y scale to be the largest number of clients + # rounded up to the nearest 10 + ymax = (clients.max.to_f / 10).ceil * 10 + ymax = 10 if ymax == 0 # In case there are no clients + # Something around 10 divisions on the y axis looks decent + ydiv = (ymax / 10).ceil + y.set_range(0, ymax, ydiv) + + title = Title.new("Number of Clients") + chart = OpenFlashChart.new + chart.set_title(title) + chart.x_axis = x + chart.y_axis = y + chart.bg_colour = '#FFFFFF' + + chart.add_element(line_dot) + + render :text => chart.to_s + end + } + end end end + Modified: trunk/server/app/views/dashboard/index.html.erb =================================================================== --- trunk/server/app/views/dashboard/index.html.erb 2009-02-06 17:39:44 UTC (rev 69) +++ trunk/server/app/views/dashboard/index.html.erb 2009-02-06 17:40:11 UTC (rev 70) @@ -5,24 +5,22 @@ <div id="dashboard_body"> -<%- total_count = Client.count -%> -<%- healthy_count = Client.count(:conditions => ["status = 0 AND updated_at > ?", 24.hours.ago]) -%> -<%- broken_count = Client.count(:conditions => ["status != 0 AND status != 200 AND updated_at > ?", 24.hours.ago]) -%> -<%- disabled_count = Client.count(:conditions => ["status = 200 AND updated_at > ?", 24.hours.ago]) -%> -<%- stale_count = Client.count(:conditions => ["updated_at <= ?", 24.hours.ago]) -%> - <table class="network_summary"> <caption>Client Summary</caption> <tbody> <tr> - <tr><td class="network_summary_left">Number of clients: </td> <td class="network_summary_right"><%= total_count == 0 ? total_count : link_to(total_count, clients_path) %></td></tr> - <tr><td>Healthy:</td> <td><%= healthy_count == 0 ? healthy_count : link_to(healthy_count, clients_path + "?health=healthy") %></td></tr> - <tr><td>Broken:</td> <td><%= broken_count == 0 ? broken_count : link_to(broken_count, clients_path + "?health=broken") %></td></tr> - <tr><td>Disabled:</td> <td><%= disabled_count == 0 ? disabled_count : link_to(disabled_count, clients_path + "?health=disabled") %></td></tr> - <tr><td>Stale:</td> <td><%= stale_count == 0 ? stale_count : link_to(stale_count, clients_path + "?health=stale") %></td></tr> + <tr><td>Number of clients:</td> <td><%= @total_count == 0 ? @total_count : link_to(@total_count, clients_path) %></td></tr> + <tr><td>Healthy:</td> <td><%= @healthy_count == 0 ? @healthy_count : link_to(@healthy_count, clients_path + "?health=healthy") %></td></tr> + <tr><td>Broken:</td> <td><%= @broken_count == 0 ? @broken_count : link_to(@broken_count, clients_path + "?health=broken") %></td></tr> + <tr><td>Disabled:</td> <td><%= @disabled_count == 0 ? @disabled_count : link_to(@disabled_count, clients_path + "?health=disabled") %></td></tr> + <tr><td>Stale:</td> <td><%= @stale_count == 0 ? @stale_count : link_to(@stale_count, clients_path + "?health=stale") %></td></tr> </tr> </tbody> </table> +<script type="text/javascript" src="/javascripts/swfobject.js"></script> +<%= @status_graph %> +<%= @client_graph %> + </div> <!-- end dashboard_body --> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2009-02-06 17:39:50
|
Revision: 69 http://etch.svn.sourceforge.net/etch/?rev=69&view=rev Author: jheiss Date: 2009-02-06 17:39:44 +0000 (Fri, 06 Feb 2009) Log Message: ----------- Add the open_flash_chart plugin. http://www.pullmonkey.com/projects/open_flash_chart2/ Added Paths: ----------- trunk/server/public/javascripts/swfobject.js trunk/server/public/open-flash-chart.swf trunk/server/vendor/plugins/open_flash_chart/ trunk/server/vendor/plugins/open_flash_chart/MIT-LICENSE trunk/server/vendor/plugins/open_flash_chart/README trunk/server/vendor/plugins/open_flash_chart/Rakefile trunk/server/vendor/plugins/open_flash_chart/assets/ trunk/server/vendor/plugins/open_flash_chart/assets/javascripts/ trunk/server/vendor/plugins/open_flash_chart/assets/javascripts/swfobject.js trunk/server/vendor/plugins/open_flash_chart/assets/open-flash-chart.swf trunk/server/vendor/plugins/open_flash_chart/init.rb trunk/server/vendor/plugins/open_flash_chart/install.rb trunk/server/vendor/plugins/open_flash_chart/lib/ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/area_base.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/area_hollow.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/area_line.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_3d.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_base.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_filled.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_glass.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_sketch.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_stack.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/base.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/candle.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/chart.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/h_bar.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/line.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/line_base.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/line_dot.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/line_hollow.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/linear_regression.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/ofc_ajax.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/open_flash_chart_object.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/pie.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/radar_axis.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/radar_axis_labels.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/radar_spoke_labels.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/scatter.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/scatter_line.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/shape.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/title.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/tooltip.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/upload_image.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/x_axis.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/x_axis_label.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/x_axis_labels.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/x_legend.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/y_axis.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/y_axis_base.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/y_axis_right.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/y_legend.rb trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart.rb trunk/server/vendor/plugins/open_flash_chart/tasks/ trunk/server/vendor/plugins/open_flash_chart/tasks/open_flash_chart_tasks.rake trunk/server/vendor/plugins/open_flash_chart/test/ trunk/server/vendor/plugins/open_flash_chart/test/open_flash_chart_test.rb trunk/server/vendor/plugins/open_flash_chart/uninstall.rb Added: trunk/server/public/javascripts/swfobject.js =================================================================== --- trunk/server/public/javascripts/swfobject.js (rev 0) +++ trunk/server/public/javascripts/swfobject.js 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,5 @@ +/* SWFObject v2.0 <http://code.google.com/p/swfobject/> + Copyright (c) 2007 Geoff Stearns, Michael Williams, and Bobby van der Sluis + This software is released under the MIT License <http://www.opensource.org/licenses/mit-license.php> +*/ +var swfobject=function(){var Z="undefined",P="object",B="Shockwave Flash",h="ShockwaveFlash.ShockwaveFlash",W="application/x-shockwave-flash",K="SWFObjectExprInst",G=window,g=document,N=navigator,f=[],H=[],Q=null,L=null,T=null,S=false,C=false;var a=function(){var l=typeof g.getElementById!=Z&&typeof g.getElementsByTagName!=Z&&typeof g.createElement!=Z&&typeof g.appendChild!=Z&&typeof g.replaceChild!=Z&&typeof g.removeChild!=Z&&typeof g.cloneNode!=Z,t=[0,0,0],n=null;if(typeof N.plugins!=Z&&typeof N.plugins[B]==P){n=N.plugins[B].description;if(n){n=n.replace(/^.*\s+(\S+\s+\S+$)/,"$1");t[0]=parseInt(n.replace(/^(.*)\..*$/,"$1"),10);t[1]=parseInt(n.replace(/^.*\.(.*)\s.*$/,"$1"),10);t[2]=/r/.test(n)?parseInt(n.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof G.ActiveXObject!=Z){var o=null,s=false;try{o=new ActiveXObject(h+".7")}catch(k){try{o=new ActiveXObject(h+".6");t=[6,0,21];o.AllowScriptAccess="always"}catch(k){if(t[0]==6){s=true}}if(!s){try{o=new ActiveXObject(h)}catch(k){}}}if(!s&&o){try{n=o.GetVariable("$version");if(n){n=n.split(" ")[1].split(",");t=[parseInt(n[0],10),parseInt(n[1],10),parseInt(n[2],10)]}}catch(k){}}}}var v=N.userAgent.toLowerCase(),j=N.platform.toLowerCase(),r=/webkit/.test(v)?parseFloat(v.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,i=false,q=j?/win/.test(j):/win/.test(v),m=j?/mac/.test(j):/mac/.test(v);/*@cc_on i=true;@if(@_win32)q=true;@elif(@_mac)m=true;@end@*/return{w3cdom:l,pv:t,webkit:r,ie:i,win:q,mac:m}}();var e=function(){if(!a.w3cdom){return }J(I);if(a.ie&&a.win){try{g.write("<script id=__ie_ondomload defer=true src=//:><\/script>");var i=c("__ie_ondomload");if(i){i.onreadystatechange=function(){if(this.readyState=="complete"){this.parentNode.removeChild(this);V()}}}}catch(j){}}if(a.webkit&&typeof g.readyState!=Z){Q=setInterval(function(){if(/loaded|complete/.test(g.readyState)){V()}},10)}if(typeof g.addEventListener!=Z){g.addEventListener("DOMContentLoaded",V,null)}M(V)}();function V(){if(S){return }if(a.ie&&a.win){var m=Y("span");try{var l=g.getElementsByTagName("body")[0].appendChild(m);l.parentNode.removeChild(l)}catch(n){return }}S=true;if(Q){clearInterval(Q);Q=null}var j=f.length;for(var k=0;k<j;k++){f[k]()}}function J(i){if(S){i()}else{f[f.length]=i}}function M(j){if(typeof G.addEventListener!=Z){G.addEventListener("load",j,false)}else{if(typeof g.addEventListener!=Z){g.addEventListener("load",j,false)}else{if(typeof G.attachEvent!=Z){G.attachEvent("onload",j)}else{if(typeof G.onload=="function"){var i=G.onload;G.onload=function(){i();j()}}else{G.onload=j}}}}}function I(){var l=H.length;for(var j=0;j<l;j++){var m=H[j].id;if(a.pv[0]>0){var k=c(m);if(k){H[j].width=k.getAttribute("width")?k.getAttribute("width"):"0";H[j].height=k.getAttribute("height")?k.getAttribute("height"):"0";if(O(H[j].swfVersion)){if(a.webkit&&a.webkit<312){U(k)}X(m,true)}else{if(H[j].expressInstall&&!C&&O("6.0.65")&&(a.win||a.mac)){D(H[j])}else{d(k)}}}}else{X(m,true)}}}function U(m){var k=m.getElementsByTagName(P)[0];if(k){var p=Y("embed"),r=k.attributes;if(r){var o=r.length;for(var n=0;n<o;n++){if(r[n].nodeName.toLowerCase()=="data"){p.setAttribute("src",r[n].nodeValue)}else{p.setAttribute(r[n].nodeName,r[n].nodeValue)}}}var q=k.childNodes;if(q){var s=q.length;for(var l=0;l<s;l++){if(q[l].nodeType==1&&q[l].nodeName.toLowerCase()=="param"){p.setAttribute(q[l].getAttribute("name"),q[l].getAttribute("value"))}}}m.parentNode.replaceChild(p,m)}}function F(i){if(a.ie&&a.win&&O("8.0.0")){G.attachEvent("onunload",function(){var k=c(i);if(k){for(var j in k){if(typeof k[j]=="function"){k[j]=function(){}}}k.parentNode.removeChild(k)}})}}function D(j){C=true;var o=c(j.id);if(o){if(j.altContentId){var l=c(j.altContentId);if(l){L=l;T=j.altContentId}}else{L=b(o)}if(!(/%$/.test(j.width))&&parseInt(j.width,10)<310){j.width="310"}if(!(/%$/.test(j.height))&&parseInt(j.height,10)<137){j.height="137"}g.title=g.title.slice(0,47)+" - Flash Player Installation";var n=a.ie&&a.win?"ActiveX":"PlugIn",k=g.title,m="MMredirectURL="+G.location+"&MMplayerType="+n+"&MMdoctitle="+k,p=j.id;if(a.ie&&a.win&&o.readyState!=4){var i=Y("div");p+="SWFObjectNew";i.setAttribute("id",p);o.parentNode.insertBefore(i,o);o.style.display="none";G.attachEvent("onload",function(){o.parentNode.removeChild(o)})}R({data:j.expressInstall,id:K,width:j.width,height:j.height},{flashvars:m},p)}}function d(j){if(a.ie&&a.win&&j.readyState!=4){var i=Y("div");j.parentNode.insertBefore(i,j);i.parentNode.replaceChild(b(j),i);j.style.display="none";G.attachEvent("onload",function(){j.parentNode.removeChild(j)})}else{j.parentNode.replaceChild(b(j),j)}}function b(n){var m=Y("div");if(a.win&&a.ie){m.innerHTML=n.innerHTML}else{var k=n.getElementsByTagName(P)[0];if(k){var o=k.childNodes;if(o){var j=o.length;for(var l=0;l<j;l++){if(!(o[l].nodeType==1&&o[l].nodeName.toLowerCase()=="param")&&!(o[l].nodeType==8)){m.appendChild(o[l].cloneNode(true))}}}}}return m}function R(AE,AC,q){var p,t=c(q);if(typeof AE.id==Z){AE.id=q}if(a.ie&&a.win){var AD="";for(var z in AE){if(AE[z]!=Object.prototype[z]){if(z=="data"){AC.movie=AE[z]}else{if(z.toLowerCase()=="styleclass"){AD+=' class="'+AE[z]+'"'}else{if(z!="classid"){AD+=" "+z+'="'+AE[z]+'"'}}}}}var AB="";for(var y in AC){if(AC[y]!=Object.prototype[y]){AB+='<param name="'+y+'" value="'+AC[y]+'" />'}}t.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+AD+">"+AB+"</object>";F(AE.id);p=c(AE.id)}else{if(a.webkit&&a.webkit<312){var AA=Y("embed");AA.setAttribute("type",W);for(var x in AE){if(AE[x]!=Object.prototype[x]){if(x=="data"){AA.setAttribute("src",AE[x])}else{if(x.toLowerCase()=="styleclass"){AA.setAttribute("class",AE[x])}else{if(x!="classid"){AA.setAttribute(x,AE[x])}}}}}for(var w in AC){if(AC[w]!=Object.prototype[w]){if(w!="movie"){AA.setAttribute(w,AC[w])}}}t.parentNode.replaceChild(AA,t);p=AA}else{var s=Y(P);s.setAttribute("type",W);for(var v in AE){if(AE[v]!=Object.prototype[v]){if(v.toLowerCase()=="styleclass"){s.setAttribute("class",AE[v])}else{if(v!="classid"){s.setAttribute(v,AE[v])}}}}for(var u in AC){if(AC[u]!=Object.prototype[u]&&u!="movie"){E(s,u,AC[u])}}t.parentNode.replaceChild(s,t);p=s}}return p}function E(k,i,j){var l=Y("param");l.setAttribute("name",i);l.setAttribute("value",j);k.appendChild(l)}function c(i){return g.getElementById(i)}function Y(i){return g.createElement(i)}function O(k){var j=a.pv,i=k.split(".");i[0]=parseInt(i[0],10);i[1]=parseInt(i[1],10);i[2]=parseInt(i[2],10);return(j[0]>i[0]||(j[0]==i[0]&&j[1]>i[1])||(j[0]==i[0]&&j[1]==i[1]&&j[2]>=i[2]))?true:false}function A(m,j){if(a.ie&&a.mac){return }var l=g.getElementsByTagName("head")[0],k=Y("style");k.setAttribute("type","text/css");k.setAttribute("media","screen");if(!(a.ie&&a.win)&&typeof g.createTextNode!=Z){k.appendChild(g.createTextNode(m+" {"+j+"}"))}l.appendChild(k);if(a.ie&&a.win&&typeof g.styleSheets!=Z&&g.styleSheets.length>0){var i=g.styleSheets[g.styleSheets.length-1];if(typeof i.addRule==P){i.addRule(m,j)}}}function X(k,i){var j=i?"visible":"hidden";if(S){c(k).style.visibility=j}else{A("#"+k,"visibility:"+j)}}return{registerObject:function(l,i,k){if(!a.w3cdom||!l||!i){return }var j={};j.id=l;j.swfVersion=i;j.expressInstall=k?k:false;H[H.length]=j;X(l,false)},getObjectById:function(l){var i=null;if(a.w3cdom&&S){var j=c(l);if(j){var k=j.getElementsByTagName(P)[0];if(!k||(k&&typeof j.SetVariable!=Z)){i=j}else{if(typeof k.SetVariable!=Z){i=k}}}}return i},embedSWF:function(n,u,r,t,j,m,k,p,s){if(!a.w3cdom||!n||!u||!r||!t||!j){return }r+="";t+="";if(O(j)){X(u,false);var q=(typeof s==P)?s:{};q.data=n;q.width=r;q.height=t;var o=(typeof p==P)?p:{};if(typeof k==P){for(var l in k){if(k[l]!=Object.prototype[l]){if(typeof o.flashvars!=Z){o.flashvars+="&"+l+"="+k[l]}else{o.flashvars=l+"="+k[l]}}}}J(function(){R(q,o,u);if(q.id==u){X(u,true)}})}else{if(m&&!C&&O("6.0.65")&&(a.win||a.mac)){X(u,false);J(function(){var i={};i.id=i.altContentId=u;i.width=r;i.height=t;i.expressInstall=m;D(i)})}}},getFlashPlayerVersion:function(){return{major:a.pv[0],minor:a.pv[1],release:a.pv[2]}},hasFlashPlayerVersion:O,createSWF:function(k,j,i){if(a.w3cdom&&S){return R(k,j,i)}else{return undefined}},createCSS:function(j,i){if(a.w3cdom){A(j,i)}},addDomLoadEvent:J,addLoadEvent:M,getQueryParamValue:function(m){var l=g.location.search||g.location.hash;if(m==null){return l}if(l){var k=l.substring(1).split("&");for(var j=0;j<k.length;j++){if(k[j].substring(0,k[j].indexOf("="))==m){return k[j].substring((k[j].indexOf("=")+1))}}}return""},expressInstallCallback:function(){if(C&&L){var i=c(K);if(i){i.parentNode.replaceChild(L,i);if(T){X(T,true);if(a.ie&&a.win){L.style.display="block"}}L=null;T=null;C=false}}}}}(); \ No newline at end of file Added: trunk/server/public/open-flash-chart.swf =================================================================== (Binary files differ) Property changes on: trunk/server/public/open-flash-chart.swf ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Added: trunk/server/vendor/plugins/open_flash_chart/MIT-LICENSE =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/MIT-LICENSE (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/MIT-LICENSE 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,20 @@ +Copyright (c) 2008 [name of plugin creator] + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Added: trunk/server/vendor/plugins/open_flash_chart/README =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/README (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/README 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,48 @@ +OpenFlashChart Version 2.0.0 11/14/2008 +============== + +1) rails ofc2_test_app +2) cd ofc2_test_app +3) script/plugin install git://github.com/pullmonkey/open_flash_chart.git +4) script/generate controller test_it + +5) Add the following to the test_it_controller.rb in RAILS_ROOT/app/controllers: +class TestItController < ApplicationController + + def index + respond_to do |wants| + wants.html { + @graph = open_flash_chart_object( 600, 300, url_for( :action => 'index', :format => :json ) ) + } + wants.json { + chart = OpenFlashChart.new( "MY TITLE" ) do |c| + c << BarGlass.new( :values => (1..10).sort_by{rand} ) + end + render :text => chart, :layout => false + } + end + end + +end + +6) Add the following to index.html.erb in RAILS_ROOT/app/views/test_it/: +<html> +<head> + <script type="text/javascript" src="/javascripts/swfobject.js"></script> +</head> +<body> +<%= @graph %> +</body> +</html> + +7) script/server +8) Let me know how it goes, thanks. + + +Example +======= + +Example above and more to follow here - http://www.pullmonkey.com/projects/open_flash_chart + + +Copyright (c) 2008 PullMonkey, released under the MIT license Added: trunk/server/vendor/plugins/open_flash_chart/Rakefile =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/Rakefile (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/Rakefile 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,22 @@ +require 'rake' +require 'rake/testtask' +require 'rake/rdoctask' + +desc 'Default: run unit tests.' +task :default => :test + +desc 'Test the open_flash_chart plugin.' +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' + t.pattern = 'test/**/*_test.rb' + t.verbose = true +end + +desc 'Generate documentation for the open_flash_chart plugin.' +Rake::RDocTask.new(:rdoc) do |rdoc| + rdoc.rdoc_dir = 'rdoc' + rdoc.title = 'OpenFlashChart' + rdoc.options << '--line-numbers' << '--inline-source' + rdoc.rdoc_files.include('README') + rdoc.rdoc_files.include('lib/**/*.rb') +end Added: trunk/server/vendor/plugins/open_flash_chart/assets/javascripts/swfobject.js =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/assets/javascripts/swfobject.js (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/assets/javascripts/swfobject.js 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,5 @@ +/* SWFObject v2.0 <http://code.google.com/p/swfobject/> + Copyright (c) 2007 Geoff Stearns, Michael Williams, and Bobby van der Sluis + This software is released under the MIT License <http://www.opensource.org/licenses/mit-license.php> +*/ +var swfobject=function(){var Z="undefined",P="object",B="Shockwave Flash",h="ShockwaveFlash.ShockwaveFlash",W="application/x-shockwave-flash",K="SWFObjectExprInst",G=window,g=document,N=navigator,f=[],H=[],Q=null,L=null,T=null,S=false,C=false;var a=function(){var l=typeof g.getElementById!=Z&&typeof g.getElementsByTagName!=Z&&typeof g.createElement!=Z&&typeof g.appendChild!=Z&&typeof g.replaceChild!=Z&&typeof g.removeChild!=Z&&typeof g.cloneNode!=Z,t=[0,0,0],n=null;if(typeof N.plugins!=Z&&typeof N.plugins[B]==P){n=N.plugins[B].description;if(n){n=n.replace(/^.*\s+(\S+\s+\S+$)/,"$1");t[0]=parseInt(n.replace(/^(.*)\..*$/,"$1"),10);t[1]=parseInt(n.replace(/^.*\.(.*)\s.*$/,"$1"),10);t[2]=/r/.test(n)?parseInt(n.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof G.ActiveXObject!=Z){var o=null,s=false;try{o=new ActiveXObject(h+".7")}catch(k){try{o=new ActiveXObject(h+".6");t=[6,0,21];o.AllowScriptAccess="always"}catch(k){if(t[0]==6){s=true}}if(!s){try{o=new ActiveXObject(h)}catch(k){}}}if(!s&&o){try{n=o.GetVariable("$version");if(n){n=n.split(" ")[1].split(",");t=[parseInt(n[0],10),parseInt(n[1],10),parseInt(n[2],10)]}}catch(k){}}}}var v=N.userAgent.toLowerCase(),j=N.platform.toLowerCase(),r=/webkit/.test(v)?parseFloat(v.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,i=false,q=j?/win/.test(j):/win/.test(v),m=j?/mac/.test(j):/mac/.test(v);/*@cc_on i=true;@if(@_win32)q=true;@elif(@_mac)m=true;@end@*/return{w3cdom:l,pv:t,webkit:r,ie:i,win:q,mac:m}}();var e=function(){if(!a.w3cdom){return }J(I);if(a.ie&&a.win){try{g.write("<script id=__ie_ondomload defer=true src=//:><\/script>");var i=c("__ie_ondomload");if(i){i.onreadystatechange=function(){if(this.readyState=="complete"){this.parentNode.removeChild(this);V()}}}}catch(j){}}if(a.webkit&&typeof g.readyState!=Z){Q=setInterval(function(){if(/loaded|complete/.test(g.readyState)){V()}},10)}if(typeof g.addEventListener!=Z){g.addEventListener("DOMContentLoaded",V,null)}M(V)}();function V(){if(S){return }if(a.ie&&a.win){var m=Y("span");try{var l=g.getElementsByTagName("body")[0].appendChild(m);l.parentNode.removeChild(l)}catch(n){return }}S=true;if(Q){clearInterval(Q);Q=null}var j=f.length;for(var k=0;k<j;k++){f[k]()}}function J(i){if(S){i()}else{f[f.length]=i}}function M(j){if(typeof G.addEventListener!=Z){G.addEventListener("load",j,false)}else{if(typeof g.addEventListener!=Z){g.addEventListener("load",j,false)}else{if(typeof G.attachEvent!=Z){G.attachEvent("onload",j)}else{if(typeof G.onload=="function"){var i=G.onload;G.onload=function(){i();j()}}else{G.onload=j}}}}}function I(){var l=H.length;for(var j=0;j<l;j++){var m=H[j].id;if(a.pv[0]>0){var k=c(m);if(k){H[j].width=k.getAttribute("width")?k.getAttribute("width"):"0";H[j].height=k.getAttribute("height")?k.getAttribute("height"):"0";if(O(H[j].swfVersion)){if(a.webkit&&a.webkit<312){U(k)}X(m,true)}else{if(H[j].expressInstall&&!C&&O("6.0.65")&&(a.win||a.mac)){D(H[j])}else{d(k)}}}}else{X(m,true)}}}function U(m){var k=m.getElementsByTagName(P)[0];if(k){var p=Y("embed"),r=k.attributes;if(r){var o=r.length;for(var n=0;n<o;n++){if(r[n].nodeName.toLowerCase()=="data"){p.setAttribute("src",r[n].nodeValue)}else{p.setAttribute(r[n].nodeName,r[n].nodeValue)}}}var q=k.childNodes;if(q){var s=q.length;for(var l=0;l<s;l++){if(q[l].nodeType==1&&q[l].nodeName.toLowerCase()=="param"){p.setAttribute(q[l].getAttribute("name"),q[l].getAttribute("value"))}}}m.parentNode.replaceChild(p,m)}}function F(i){if(a.ie&&a.win&&O("8.0.0")){G.attachEvent("onunload",function(){var k=c(i);if(k){for(var j in k){if(typeof k[j]=="function"){k[j]=function(){}}}k.parentNode.removeChild(k)}})}}function D(j){C=true;var o=c(j.id);if(o){if(j.altContentId){var l=c(j.altContentId);if(l){L=l;T=j.altContentId}}else{L=b(o)}if(!(/%$/.test(j.width))&&parseInt(j.width,10)<310){j.width="310"}if(!(/%$/.test(j.height))&&parseInt(j.height,10)<137){j.height="137"}g.title=g.title.slice(0,47)+" - Flash Player Installation";var n=a.ie&&a.win?"ActiveX":"PlugIn",k=g.title,m="MMredirectURL="+G.location+"&MMplayerType="+n+"&MMdoctitle="+k,p=j.id;if(a.ie&&a.win&&o.readyState!=4){var i=Y("div");p+="SWFObjectNew";i.setAttribute("id",p);o.parentNode.insertBefore(i,o);o.style.display="none";G.attachEvent("onload",function(){o.parentNode.removeChild(o)})}R({data:j.expressInstall,id:K,width:j.width,height:j.height},{flashvars:m},p)}}function d(j){if(a.ie&&a.win&&j.readyState!=4){var i=Y("div");j.parentNode.insertBefore(i,j);i.parentNode.replaceChild(b(j),i);j.style.display="none";G.attachEvent("onload",function(){j.parentNode.removeChild(j)})}else{j.parentNode.replaceChild(b(j),j)}}function b(n){var m=Y("div");if(a.win&&a.ie){m.innerHTML=n.innerHTML}else{var k=n.getElementsByTagName(P)[0];if(k){var o=k.childNodes;if(o){var j=o.length;for(var l=0;l<j;l++){if(!(o[l].nodeType==1&&o[l].nodeName.toLowerCase()=="param")&&!(o[l].nodeType==8)){m.appendChild(o[l].cloneNode(true))}}}}}return m}function R(AE,AC,q){var p,t=c(q);if(typeof AE.id==Z){AE.id=q}if(a.ie&&a.win){var AD="";for(var z in AE){if(AE[z]!=Object.prototype[z]){if(z=="data"){AC.movie=AE[z]}else{if(z.toLowerCase()=="styleclass"){AD+=' class="'+AE[z]+'"'}else{if(z!="classid"){AD+=" "+z+'="'+AE[z]+'"'}}}}}var AB="";for(var y in AC){if(AC[y]!=Object.prototype[y]){AB+='<param name="'+y+'" value="'+AC[y]+'" />'}}t.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+AD+">"+AB+"</object>";F(AE.id);p=c(AE.id)}else{if(a.webkit&&a.webkit<312){var AA=Y("embed");AA.setAttribute("type",W);for(var x in AE){if(AE[x]!=Object.prototype[x]){if(x=="data"){AA.setAttribute("src",AE[x])}else{if(x.toLowerCase()=="styleclass"){AA.setAttribute("class",AE[x])}else{if(x!="classid"){AA.setAttribute(x,AE[x])}}}}}for(var w in AC){if(AC[w]!=Object.prototype[w]){if(w!="movie"){AA.setAttribute(w,AC[w])}}}t.parentNode.replaceChild(AA,t);p=AA}else{var s=Y(P);s.setAttribute("type",W);for(var v in AE){if(AE[v]!=Object.prototype[v]){if(v.toLowerCase()=="styleclass"){s.setAttribute("class",AE[v])}else{if(v!="classid"){s.setAttribute(v,AE[v])}}}}for(var u in AC){if(AC[u]!=Object.prototype[u]&&u!="movie"){E(s,u,AC[u])}}t.parentNode.replaceChild(s,t);p=s}}return p}function E(k,i,j){var l=Y("param");l.setAttribute("name",i);l.setAttribute("value",j);k.appendChild(l)}function c(i){return g.getElementById(i)}function Y(i){return g.createElement(i)}function O(k){var j=a.pv,i=k.split(".");i[0]=parseInt(i[0],10);i[1]=parseInt(i[1],10);i[2]=parseInt(i[2],10);return(j[0]>i[0]||(j[0]==i[0]&&j[1]>i[1])||(j[0]==i[0]&&j[1]==i[1]&&j[2]>=i[2]))?true:false}function A(m,j){if(a.ie&&a.mac){return }var l=g.getElementsByTagName("head")[0],k=Y("style");k.setAttribute("type","text/css");k.setAttribute("media","screen");if(!(a.ie&&a.win)&&typeof g.createTextNode!=Z){k.appendChild(g.createTextNode(m+" {"+j+"}"))}l.appendChild(k);if(a.ie&&a.win&&typeof g.styleSheets!=Z&&g.styleSheets.length>0){var i=g.styleSheets[g.styleSheets.length-1];if(typeof i.addRule==P){i.addRule(m,j)}}}function X(k,i){var j=i?"visible":"hidden";if(S){c(k).style.visibility=j}else{A("#"+k,"visibility:"+j)}}return{registerObject:function(l,i,k){if(!a.w3cdom||!l||!i){return }var j={};j.id=l;j.swfVersion=i;j.expressInstall=k?k:false;H[H.length]=j;X(l,false)},getObjectById:function(l){var i=null;if(a.w3cdom&&S){var j=c(l);if(j){var k=j.getElementsByTagName(P)[0];if(!k||(k&&typeof j.SetVariable!=Z)){i=j}else{if(typeof k.SetVariable!=Z){i=k}}}}return i},embedSWF:function(n,u,r,t,j,m,k,p,s){if(!a.w3cdom||!n||!u||!r||!t||!j){return }r+="";t+="";if(O(j)){X(u,false);var q=(typeof s==P)?s:{};q.data=n;q.width=r;q.height=t;var o=(typeof p==P)?p:{};if(typeof k==P){for(var l in k){if(k[l]!=Object.prototype[l]){if(typeof o.flashvars!=Z){o.flashvars+="&"+l+"="+k[l]}else{o.flashvars=l+"="+k[l]}}}}J(function(){R(q,o,u);if(q.id==u){X(u,true)}})}else{if(m&&!C&&O("6.0.65")&&(a.win||a.mac)){X(u,false);J(function(){var i={};i.id=i.altContentId=u;i.width=r;i.height=t;i.expressInstall=m;D(i)})}}},getFlashPlayerVersion:function(){return{major:a.pv[0],minor:a.pv[1],release:a.pv[2]}},hasFlashPlayerVersion:O,createSWF:function(k,j,i){if(a.w3cdom&&S){return R(k,j,i)}else{return undefined}},createCSS:function(j,i){if(a.w3cdom){A(j,i)}},addDomLoadEvent:J,addLoadEvent:M,getQueryParamValue:function(m){var l=g.location.search||g.location.hash;if(m==null){return l}if(l){var k=l.substring(1).split("&");for(var j=0;j<k.length;j++){if(k[j].substring(0,k[j].indexOf("="))==m){return k[j].substring((k[j].indexOf("=")+1))}}}return""},expressInstallCallback:function(){if(C&&L){var i=c(K);if(i){i.parentNode.replaceChild(L,i);if(T){X(T,true);if(a.ie&&a.win){L.style.display="block"}}L=null;T=null;C=false}}}}}(); \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/assets/open-flash-chart.swf =================================================================== (Binary files differ) Property changes on: trunk/server/vendor/plugins/open_flash_chart/assets/open-flash-chart.swf ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Added: trunk/server/vendor/plugins/open_flash_chart/init.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/init.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/init.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,9 @@ +require 'open_flash_chart' + +ActionView::Base.send :include, OpenFlashChart::View +OpenFlashChart::Base.send :include, OpenFlashChart::View +ActionController::Base.send :include, OpenFlashChart::Controller +ActionController::Base.send :include, OpenFlashChart +ActiveRecord::Base.send :include, OpenFlashChart::View +ActiveRecord::Base.send :include, OpenFlashChart::Controller +ActiveRecord::Base.send :include, OpenFlashChart \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/install.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/install.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/install.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,17 @@ +# Workaround a problem with script/plugin and http-based repos. +# See http://dev.rubyonrails.org/ticket/8189 +Dir.chdir(Dir.getwd.sub(/vendor.*/, '')) do + + ## + ## Copy over asset files (javascript/css/images) from the plugin directory to public/ + ## + + def copy_files(source_path, destination_path, directory) + source, destination = File.join(directory, source_path), File.join(RAILS_ROOT, destination_path) + # FileUtils.mkdir(destination) unless File.exist?(destination) + FileUtils.cp_r(Dir.glob(source+'/*.*'), destination) + end + + directory = File.dirname(__FILE__) + copy_files("/assets", "/public", directory) +end Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/area_base.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/area_base.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/area_base.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,17 @@ +module OpenFlashChart + class AreaBase < Base + def initialize args={} + super + @fill_alpha = 0.35 + @values = [] + end + + def set_fill_colour(color) + @fill = color + end + + def set_loop + @loop = true + end + end +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/area_hollow.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/area_hollow.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/area_hollow.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,10 @@ +module OpenFlashChart + + class AreaHollow < AreaBase + def initialize args={} + super + @type = "area_hollow" + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/area_line.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/area_line.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/area_line.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,10 @@ +module OpenFlashChart + + class AreaLine < AreaBase + def initialize args={} + super + @type = "area_line" + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,18 @@ +module OpenFlashChart + + class Bar < BarBase + def initialize args={} + super + @type = "bar" + end + end + + class BarValue < Base + def initialize( top, bottom=nil, args={} ) + @top = top + @bottom = bottom + super args + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_3d.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_3d.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_3d.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,17 @@ +module OpenFlashChart + + class Bar3d < BarBase + def initialize args={} + super + @type = "bar_3d" + end + end + + class Bar3dValue < Base + def initialize(top, args={}) + @top = top + super args + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_base.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_base.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_base.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,3 @@ +module OpenFlashChart + class BarBase < Base; end +end Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_filled.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_filled.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_filled.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,18 @@ +module OpenFlashChart + + class BarFilled < BarBase + def initialize(colour=nil, outline_colour=nil, args={}) + super args + @type = "bar_filled" + @colour = colour + @outline_colour = outline_colour + end + end + + class BarFilledValue < BarValue + def initialize(top, bottom=nil, args={}) + super + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_glass.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_glass.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_glass.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,17 @@ +module OpenFlashChart + + class BarGlass < BarBase + def initialize args={} + super + @type = "bar_glass" + end + end + + class BarGlassValue < Base + def initialize(top, args={}) + @top = top + super args + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_sketch.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_sketch.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_sketch.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,13 @@ +module OpenFlashChart + + class BarSketch < BarBase + def initialize(colour, outline_colour, fun_factor, args = {} ) + super args + @type = "bar_sketch" + @colour = colour + @outline_colour = outline_colour + @offset = fun_factor + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_stack.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_stack.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/bar_stack.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,20 @@ +module OpenFlashChart + + class BarStack < BarBase + def initialize args={} + super + @type = "bar_stack" + end + + alias_method :append_stack, :append_value + end + + class BarStackValue < Base + def initialize(val,colour, args={}) + @val = val + @colour = colour + super + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/base.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/base.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/base.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,102 @@ +module OpenFlashChart + class Base + + def initialize(args={}) + # set all the instance variables we want + # assuming something like this OpenFlashChart.new(:x_axis => 5, :y_axis => 10, :elements => ["one", "two"], ...) + args.each do |k,v| + self.instance_variable_set("@#{k}", v) + end + yield self if block_given? # magic pen pattern + end + + # same as to_s but won't stack overflow ... use this instead of to_s + def render + # need to return the following like this + # 1) font_size as font-size + # 2) dot_size as dot-size + # 3) outline_colour as outline-colour + # 4) halo_size as halo-size + # 5) start_angle as start-angle + # 6) tick_height as tick-height + # 7) grid_colour as grid-colour + # 8) threed as 3d + # 9) tick_length as tick-length + returning self.to_json2 do |output| + output.gsub!("threed","3d") + %w(font_size dot_size outline_colour halo_size start_angle tick_height grid_colour tick_length no_labels label_colour gradient_fill fill_alpha on_click spoke_labels).each do |replace| + output.gsub!(replace, replace.gsub("_", "-")) + end + end + end + + def to_json2 + self.instance_values.to_json + end + + alias_method :to_s, :render + + def add_element(element) + @elements ||= [] + @elements << element + end + + def <<(e) + add_element e + end + + def set_key(text, size) + @text = text + @font_size = size + end + + def append_value(v) + @values ||= [] + @values << v + end + + def set_range(min,max,steps=1) + @min = min + @max = max + @steps = steps + end + + def set_offset(v) + @offset = v ? true : false + end + + def set_colours(colour, grid_colour) + @colour = colour + @grid_colour = grid_colour + end + + def set_tooltip(tip) + if tip.is_a?(Tooltip) + #we have a style for our chart's tooltips + @tooltip = tip + else + # the user could just use set_tip(tip) or tip=(tip) to just set the text of the tooltip + @tip = tip + end + end + alias_method "tooltip=", :set_tooltip + + + + def method_missing(method_name, *args, &blk) + case method_name.to_s + when /(.*)=/ # i.e., if it is something x_legend= + # if the user wants to set an instance variable then let them + # the other args (args[0]) are ignored since it is a set method + self.instance_variable_set("@#{$1}", args[0]) + when /^set_(.*)/ + # backwards compatible ... the user can still use the same set_y_legend methods if they want + self.instance_variable_set("@#{$1}", args[0]) + else + # if the method/attribute is missing and it is not a set method then hmmmm better let the user know + super + end + end + + end +end Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/candle.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/candle.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/candle.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,20 @@ +module OpenFlashChart + + class Candle < Base + def initialize(args={}) + super args + @type = "candle" + end + end + + class CandleValue < Base + def initialize( top, bottom, low, high, args={} ) + @top = top + @bottom = bottom + @low = low + @high = high + super args + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/chart.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/chart.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/chart.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,13 @@ +module OpenFlashChart + + class Chart < Base + def initialize( title=nil, args={}) + super args + @title = Title.new( title ) if title + end + end + + class OpenFlashChart < Chart + end + +end Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/h_bar.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/h_bar.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/h_bar.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,26 @@ +module OpenFlashChart + + class HBarValue < Base + def initialize(left,right=nil, args={}) + super args + @left = left + @right = right || left + end + end + + class HBar < Base + def initialize(colour="#9933CC", args={}) + super args + @type = "hbar" + @colour = colour + @values = [] + end + + def set_values(v) + v.each do |val| + append_value(HBarValue.new(val)) + end + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/line.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/line.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/line.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,10 @@ +module OpenFlashChart + + class Line < LineBase + def initialize args={} + super + @type = "line" + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/line_base.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/line_base.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/line_base.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,17 @@ +module OpenFlashChart + + class LineBase < Base + def initialize args={} + super + @type = "line_dot" + @text = "Page Views" + @font_size = 10 + @values = [9,6,7,9,5,7,6,9,7] + end + + def loop + @loop = true + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/line_dot.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/line_dot.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/line_dot.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,17 @@ +module OpenFlashChart + + class LineDot < LineBase + def initialize args={} + super + @type = "line_dot" + end + end + + class DotValue < Base + def initialize(value, colour, args={}) + @value = value + @colour = colour + super(args) + end + end +end Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/line_hollow.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/line_hollow.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/line_hollow.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,10 @@ +module OpenFlashChart + + class LineHollow < LineBase + def initialize args={} + super + @type = "line_hollow" + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/linear_regression.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/linear_regression.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/linear_regression.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,39 @@ +# by David Lowenfels @ InternautDesign.com +# example usage: fitted_data = LinearRegression.new(data).fit + +class LinearRegression + attr_accessor :slope, :offset + + def initialize dx, dy=nil + @size = dx.size + if @size == 1 + @slope, @offset = 1,0 + return + end + dy,dx = dx,axis() unless dy # make 2D if given 1D + raise "arguments not same length!" unless @size == dy.size + sxx = sxy = sx = sy = 0 + dx.zip(dy).each do |x,y| + sxy += x*y + sxx += x*x + sx += x + sy += y + end + @slope = ( @size * sxy - sx*sy ) / ( @size * sxx - sx * sx ) + @offset = (sy - @slope*sx) / @size + end + + def fit + return axis.map{|data| predict(data) } + end + + private + + def predict( x ) + y = @slope * x + @offset + end + + def axis + (0...@size).to_a + end +end Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/ofc_ajax.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/ofc_ajax.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/ofc_ajax.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,90 @@ +module OpenFlashChart + module View + def periodically_call_function(function, options = {}) + frequency = options[:frequency] || 10 # every ten seconds by default + code = "new PeriodicalExecuter(function() {#{function}}, #{frequency})" + ActionView::Base.new.javascript_tag(code) + end + + def js_open_flash_chart_object(div_name, width, height, base="/") + <<-OUTPUT + <script type="text/javascript"> + swfobject.embedSWF("#{base}open-flash-chart.swf", "#{div_name}", "#{width}", "#{height}", "9.0.0"); + </script> + #{self.to_open_flash_chart_data} + <div id="#{div_name}"></div> + OUTPUT + end + + def link_to_ofc_load(link_text, div_name) + data_name = "#{link_text.gsub(" ","_")}_#{div_name.gsub(" ","_")}" + <<-OUTPUT + <script type="text/javascript"> + function load_#{data_name}() { + tmp_#{div_name} = findSWF("#{div_name}"); + x = tmp_#{div_name}.load(Object.toJSON(data_#{data_name})); + } + var data_#{data_name} = #{self.render}; + </script> + #{ActionView::Base.new.link_to_function link_text, "load_#{data_name}()"} + OUTPUT + end + + def link_to_remote_ofc_load(link_text, div_name, url) + fx_name = "#{link_text.gsub(" ","_")}_#{div_name.gsub(" ","_")}" + <<-OUTPUT + <script type="text/javascript"> + function reload_#{fx_name}() { + tmp_#{div_name} = findSWF("#{div_name}"); + new Ajax.Request('#{url}', { + method : 'get', + onSuccess : function(obj) {tmp_#{div_name}.load(obj.responseText);}, + onFailure : function(obj) {alert("Failed to request #{url}");}}); + } + </script> + #{ActionView::Base.new.link_to_function link_text, "reload_#{fx_name}()"} + OUTPUT + end + + def periodically_call_to_remote_ofc_load(div_name, url, options={}) + fx_name = "#{div_name.gsub(" ","_")}" + # fix a bug in rails with url_for + url = url.gsub("&","&") + <<-OUTPUT + <script type="text/javascript"> + function reload_#{fx_name}() { + tmp_#{div_name} = findSWF("#{div_name}"); + new Ajax.Request('#{url}', { + method : 'get', + onSuccess : function(obj) {tmp_#{div_name}.load(obj.responseText);}, + onFailure : function(obj) {alert("Failed to request #{url}");}}); + } + </script> + #{periodically_call_function("reload_#{fx_name}()", options)} + OUTPUT + end + + + def to_open_flash_chart_data + # this builds the open_flash_chart_data js function + <<-OUTPUT + <script type="text/javascript"> + function ofc_ready() { + } + function open_flash_chart_data() { + return Object.toJSON(data); + } + function findSWF(movieName) { + if (navigator.appName.indexOf("Microsoft")!= -1) { + return window[movieName]; + } else { + return document[movieName]; + } + } + var data = #{self.render}; + </script> + OUTPUT + end + + end +end Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/open_flash_chart_object.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/open_flash_chart_object.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/open_flash_chart_object.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,36 @@ +require 'digest/sha1' + +module OpenFlashChart + module Controller + def open_flash_chart_object(width, height, url, use_swfobject=true, base="/") + url = CGI::escape(url) + # need something that will not be repeated on the same request + special_hash = Base64.encode64(Digest::SHA1.digest("#{rand(1<<64)}/#{Time.now.to_f}/#{Process.pid}/#{url}"))[0..7] + # only good characters for our div + special_hash = special_hash.gsub(/[^a-zA-Z0-9]/,rand(10).to_s) + obj_id = "chart_#{special_hash}" # some sequencing without all the work of tracking it + div_name = "flash_content_#{special_hash}" + protocol = "http" # !request.nil? ? request.env["HTTPS"] || "http" : "http" + + # NOTE: users should put this in the <head> section themselves: + ## <script type="text/javascript" src="#{base}/javascripts/swfobject.js"></script> + + <<-HTML + <div id="#{div_name}"></div> + <script type="text/javascript"> + swfobject.embedSWF("#{base}open-flash-chart.swf", "#{div_name}", "#{width}", "#{height}", "9.0.0", "expressInstall.swf",{"data-file":"#{url}"}, {"wmode":"transparent"}); + </script> + <noscript> + <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="#{protocol}://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0" width="#{width}" height="#{height}" id="#{obj_id}" align="middle" wmode="transparent"> + <param name="allowScriptAccess" value="sameDomain" /> + <param name="movie" value="#{base}open-flash-chart.swf?data=#{url}" /> + <param name="quality" value="high" /> + <param name="bgcolor" value="#FFFFFF" /> + <embed src="#{base}open-flash-chart.swf?data=#{url}" quality="high" bgcolor="#FFFFFF" width="#{width}" height="#{height}" name="#{obj_id}" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="#{protocol}://www.macromedia.com/go/getflashplayer" id="#{obj_id}" /> + </object> + </noscript> + HTML + end + end + +end Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/pie.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/pie.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/pie.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,38 @@ +module OpenFlashChart + + class PieValue < Base + def initialize(value, label, args={}) + super args + @value = value + @label = label + end + + def set_label(label, label_color, font_size) + self.label = label + self.label_colour = label_color + self.font_size = font_size + end + + def on_click(event) + @on_click = event + end + end + + class Pie < Base + def initialize args={} + @type = "pie" + @colours = ["#d01f3c","#356aa0","#C79810"] + @border = 2 + super + end + + def set_no_labels + self.no_labels = true + end + + def on_click(event) + @on_click = event + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/radar_axis.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/radar_axis.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/radar_axis.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,10 @@ +module OpenFlashChart + + class RadarAxis < Base + def initialize(max, args={}) + super args + @max = max + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/radar_axis_labels.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/radar_axis_labels.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/radar_axis_labels.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,10 @@ +module OpenFlashChart + + class RadarAxisLabels < Base + def initialize(labels, args={}) + super args + @labels = labels + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/radar_spoke_labels.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/radar_spoke_labels.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/radar_spoke_labels.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,10 @@ +module OpenFlashChart + + class RadarSpokeLabels < Base + def initialize(labels, args={}) + super args + @labels = labels + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/scatter.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/scatter.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/scatter.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,21 @@ +module OpenFlashChart + + class ScatterValue < Base + def initialize(x,y,dot_size=nil, args={}) + super args + @x = x + @y = y + @dot_size = dot_size if dot_size.to_i > 0 + end + end + + class Scatter < Base + def initialize(colour, dot_size, args={}) + @type = "scatter" + @colour = colour + @dot_size = dot_size + super args + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/scatter_line.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/scatter_line.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/scatter_line.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,12 @@ +module OpenFlashChart + + class ScatterLine < Base + def initialize(colour, dot_size, args={}) + super args + @type = 'scatter_line' + @colour = colour + @dot_size = dot_size + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/shape.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/shape.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/shape.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,20 @@ +module OpenFlashChart + + class ShapePoint < Base + def initialize(x, y, args={}) + super args + @x = x + @y = y + end + end + + class Shape < Base + def initialize(colour, args={}) + @type = "shape" + @colour = colour + @values = [] + super args + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/title.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/title.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/title.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,10 @@ +module OpenFlashChart + + class Title < Base + def initialize(text='', args = {}) + super args + @text = text + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/tooltip.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/tooltip.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/tooltip.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,25 @@ +module OpenFlashChart + + class Tooltip < Base + def set_body_style(style) + @body = style + end + + def set_title_style(style) + @title = style + end + + def set_background_colour(bg) + @background = bg + end + + def set_proximity + @mouse = 1 + end + + def set_hover + @mouse = 2 + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/upload_image.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/upload_image.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/upload_image.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1 @@ +# TODO Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/x_axis.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/x_axis.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/x_axis.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,18 @@ +module OpenFlashChart + + class XAxis < Base + def set_3d(v) + @threed = v + end + # for some reason the json that needs to be produced is like this: + # "x_axis": { "offset": false, "labels": { "labels": [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ] } } + # note the "labels":{"labels": ....} + def set_labels(labels) + @labels = labels + @labels = {:labels => labels} unless labels.is_a?(XAxisLabels) + end + + alias_method :labels=, :set_labels + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/x_axis_label.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/x_axis_label.rb (rev 0) +++ trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/x_axis_label.rb 2009-02-06 17:39:44 UTC (rev 69) @@ -0,0 +1,21 @@ +module OpenFlashChart + + class XAxisLabel < Base + def initialize(text, colour, size, rotate, args={}) + super args + @text = text + @colour = colour + @size = size + @rotate = rotate + end + + def set_vertical + @rotate = "vertical" + end + + def set_visible + @visible = true + end + end + +end \ No newline at end of file Added: trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/x_axis_labels.rb =================================================================== --- trunk/server/vendor/plugins/open_flash_chart/lib/open_flash_chart/x_axis_labels.rb ... [truncated message content] |
From: <jh...@us...> - 2009-02-06 17:38:20
|
Revision: 68 http://etch.svn.sourceforge.net/etch/?rev=68&view=rev Author: jheiss Date: 2009-02-06 17:38:17 +0000 (Fri, 06 Feb 2009) Log Message: ----------- Force an update of the client's updated_at field so that clients that are in a stable state don't appear to go stale in our stats. Modified Paths: -------------- trunk/server/app/controllers/results_controller.rb Modified: trunk/server/app/controllers/results_controller.rb =================================================================== --- trunk/server/app/controllers/results_controller.rb 2009-02-06 17:26:36 UTC (rev 67) +++ trunk/server/app/controllers/results_controller.rb 2009-02-06 17:38:17 UTC (rev 68) @@ -122,6 +122,10 @@ end client.status = params[:status] client.message = params[:message] + # This forces an update of updated_at even if status/message haven't + # changed. Otherwise clients will appear to go stale if their state + # remains unchanged. + client.updated_at = Time.now client.save success_count = 0 params[:results].each do |result| This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2009-02-06 17:26:38
|
Revision: 67 http://etch.svn.sourceforge.net/etch/?rev=67&view=rev Author: jheiss Date: 2009-02-06 17:26:36 +0000 (Fri, 06 Feb 2009) Log Message: ----------- Replace @content_for_layout with a call to yield. @content_for_layout is deprecated. Modified Paths: -------------- trunk/server/app/views/layouts/application.html.erb Modified: trunk/server/app/views/layouts/application.html.erb =================================================================== --- trunk/server/app/views/layouts/application.html.erb 2009-02-06 17:25:40 UTC (rev 66) +++ trunk/server/app/views/layouts/application.html.erb 2009-02-06 17:26:36 UTC (rev 67) @@ -41,7 +41,8 @@ <div id="error"><%= flash[:error] %></div> <% end -%> -<%= @content_for_layout %> +<%- # Calling yield here triggers the insertion of the specific view -%> +<%= yield %> <hr /> </div> <!-- end content --> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2009-02-06 17:25:42
|
Revision: 66 http://etch.svn.sourceforge.net/etch/?rev=66&view=rev Author: jheiss Date: 2009-02-06 17:25:40 +0000 (Fri, 06 Feb 2009) Log Message: ----------- Update the relationships with other models Modified Paths: -------------- trunk/server/app/models/client.rb Modified: trunk/server/app/models/client.rb =================================================================== --- trunk/server/app/models/client.rb 2009-02-06 17:23:12 UTC (rev 65) +++ trunk/server/app/models/client.rb 2009-02-06 17:25:40 UTC (rev 66) @@ -1,7 +1,8 @@ class Client < ActiveRecord::Base has_many :facts, :dependent => :destroy - has_many :configs, :dependent => :destroy + has_many :originals, :dependent => :destroy + has_many :etch_configs, :dependent => :destroy has_many :results, :dependent => :destroy validates_presence_of :name This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2009-02-06 17:23:15
|
Revision: 65 http://etch.svn.sourceforge.net/etch/?rev=65&view=rev Author: jheiss Date: 2009-02-06 17:23:12 +0000 (Fri, 06 Feb 2009) Log Message: ----------- Add tests for duplicate and contradictory instructions Modified Paths: -------------- trunk/test/TODO trunk/test/delete.rb trunk/test/file.rb trunk/test/link.rb Modified: trunk/test/TODO =================================================================== --- trunk/test/TODO 2009-02-06 17:22:39 UTC (rev 64) +++ trunk/test/TODO 2009-02-06 17:23:12 UTC (rev 65) @@ -1,8 +1,6 @@ directory Basic operation Owner/group/perms - -config.xml: Etch aborts when given contradictory instructions Command-line options: Modified: trunk/test/delete.rb =================================================================== --- trunk/test/delete.rb 2009-02-06 17:22:39 UTC (rev 64) +++ trunk/test/delete.rb 2009-02-06 17:23:12 UTC (rev 65) @@ -164,6 +164,70 @@ # the assert within run_etch. assert(!File.exist?(@targetfile) && !File.symlink?(@targetfile), testname) + # + # Test duplicate script instructions + # + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <delete> + <script>source</script> + <script>source</script> + </delete> + </config> + EOF + end + + File.open(@targetfile, 'w') do |file| + file.puts('Original contents') + end + + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.puts("@contents << 'true'") + end + + # Run etch + #puts "Running duplicate script instructions test" + run_etch(@port, @testbase) + + assert(!File.exist?(@targetfile), 'duplicate script instructions') + + # + # Test contradictory script instructions + # + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <delete> + <script>source</script> + <script>source2</script> + </delete> + </config> + EOF + end + + File.open(@targetfile, 'w') do |file| + file.puts('Original contents') + end + + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.puts("@contents << 'true'") + end + File.open("#{@repodir}/source/#{@targetfile}/source2", 'w') do |file| + file.puts("@contents << 'true'") + end + + # Run etch + #puts "Running contradictory script instructions test" + run_etch(@port, @testbase, true) + + # Verify that the file wasn't removed + assert(File.exist?(@targetfile), 'contradictory script instructions') + end def teardown Modified: trunk/test/file.rb =================================================================== --- trunk/test/file.rb 2009-02-06 17:22:39 UTC (rev 64) +++ trunk/test/file.rb 2009-02-06 17:23:12 UTC (rev 65) @@ -427,6 +427,232 @@ # And verify that the file contents didn't change assert_equal(testcontents, get_file_contents(@targetfile), 'always_manage_metadata contents') + + # + # Test duplicate plain instructions + # + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <file> + <warning_file/> + <source> + <plain>source</plain> + <plain>source</plain> + </source> + </file> + </config> + EOF + end + + origcontents = "This is the original contents\n" + File.chmod(0644, @targetfile) # Need to give ourselves write perms + File.open(@targetfile, 'w') do |file| + file.write(origcontents) + end + sourcecontents = "This is the source contents\n" + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.write(sourcecontents) + end + + # Run etch + #puts "Running duplicate plain instructions test" + run_etch(@port, @testbase) + + # Verify that the file contents were updated + assert_equal(sourcecontents, get_file_contents(@targetfile), 'duplicate plain instructions') + + # + # Test contradictory plain instructions + # + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <file> + <source> + <plain>source</plain> + <plain>source2</plain> + </source> + </file> + </config> + EOF + end + + origcontents = "This is the original contents\n" + File.chmod(0644, @targetfile) # Need to give ourselves write perms + File.open(@targetfile, 'w') do |file| + file.write(origcontents) + end + sourcecontents = "This is the first source contents\n" + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.write(sourcecontents) + end + source2contents = "This is the second source contents\n" + File.open("#{@repodir}/source/#{@targetfile}/source2", 'w') do |file| + file.write(source2contents) + end + + # Run etch + #puts "Running contradictory plain instructions test" + run_etch(@port, @testbase, true) + + # Verify that the file contents didn't change + assert_equal(origcontents, get_file_contents(@targetfile), 'contradictory plain instructions') + + # + # Test duplicate template instructions + # + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <file> + <warning_file/> + <source> + <template>source</template> + <template>source</template> + </source> + </file> + </config> + EOF + end + + origcontents = "This is the original contents\n" + File.chmod(0644, @targetfile) # Need to give ourselves write perms + File.open(@targetfile, 'w') do |file| + file.write(origcontents) + end + sourcecontents = "This is the source contents\n" + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.write(sourcecontents) + end + + # Run etch + #puts "Running duplicate template instructions test" + run_etch(@port, @testbase) + + # Verify that the file contents were updated + assert_equal(sourcecontents, get_file_contents(@targetfile), 'duplicate template instructions') + + # + # Test contradictory template instructions + # + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <file> + <source> + <template>source</template> + <template>source2</template> + </source> + </file> + </config> + EOF + end + + origcontents = "This is the original contents\n" + File.chmod(0644, @targetfile) # Need to give ourselves write perms + File.open(@targetfile, 'w') do |file| + file.write(origcontents) + end + sourcecontents = "This is the first source contents\n" + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.write(sourcecontents) + end + source2contents = "This is the second source contents\n" + File.open("#{@repodir}/source/#{@targetfile}/source2", 'w') do |file| + file.write(source2contents) + end + + # Run etch + #puts "Running contradictory template instructions test" + run_etch(@port, @testbase, true) + + # Verify that the file contents didn't change + assert_equal(origcontents, get_file_contents(@targetfile), 'contradictory template instructions') + + # + # Test duplicate script instructions + # + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <file> + <warning_file/> + <source> + <script>source</script> + <script>source</script> + </source> + </file> + </config> + EOF + end + + origcontents = "This is the original contents\n" + File.chmod(0644, @targetfile) # Need to give ourselves write perms + File.open(@targetfile, 'w') do |file| + file.write(origcontents) + end + sourcecontents = "This is the source contents\n" + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.puts("@contents << '#{sourcecontents}'") + end + + # Run etch + #puts "Running duplicate script instructions test" + run_etch(@port, @testbase) + + # Verify that the file contents were updated + assert_equal(sourcecontents, get_file_contents(@targetfile), 'duplicate script instructions') + + # + # Test contradictory script instructions + # + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <file> + <source> + <script>source</script> + <script>source2</script> + </source> + </file> + </config> + EOF + end + + origcontents = "This is the original contents\n" + File.chmod(0644, @targetfile) # Need to give ourselves write perms + File.open(@targetfile, 'w') do |file| + file.write(origcontents) + end + sourcecontents = "This is the first source contents\n" + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.write(sourcecontents) + end + source2contents = "This is the second source contents\n" + File.open("#{@repodir}/source/#{@targetfile}/source2", 'w') do |file| + file.write(source2contents) + end + + # Run etch + #puts "Running contradictory script instructions test" + run_etch(@port, @testbase, true) + + # Verify that the file contents didn't change + assert_equal(origcontents, get_file_contents(@targetfile), 'contradictory script instructions') + end def teardown Modified: trunk/test/link.rb =================================================================== --- trunk/test/link.rb 2009-02-06 17:22:39 UTC (rev 64) +++ trunk/test/link.rb 2009-02-06 17:23:12 UTC (rev 65) @@ -219,6 +219,116 @@ # Verify that the link permissions got set correctly perms = File.lstat(@targetfile).mode & 07777 assert_equal(0777, perms, 'link perms') + + # + # Test duplicate dest instructions + # + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <link> + <dest>#{@destfile}</dest> + <dest>#{@destfile}</dest> + </link> + </config> + EOF + end + + File.delete(@targetfile) + + # Run etch + #puts "Running duplicate dest instructions test" + run_etch(@port, @testbase) + + assert_equal(@destfile, File.readlink(@targetfile), 'duplicate dest instructions') + + # + # Test contradictory dest instructions + # + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <link> + <dest>#{@destfile}</dest> + <dest>#{@destfile2}</dest> + </link> + </config> + EOF + end + + File.delete(@targetfile) if File.symlink?(@targetfile) + + # Run etch + #puts "Running contradictory dest instructions test" + run_etch(@port, @testbase, true) + + # Verify that the link wasn't created + assert(!File.symlink?(@targetfile) && !File.exist?(@targetfile), 'contradictory dest instructions') + + # + # Test duplicate script instructions + # + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <link> + <script>source</script> + <script>source</script> + </link> + </config> + EOF + end + + File.delete(@targetfile) if File.symlink?(@targetfile) + + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.puts("@contents << '#{@destfile}'") + end + + # Run etch + #puts "Running duplicate script instructions test" + run_etch(@port, @testbase) + + assert_equal(@destfile, File.readlink(@targetfile), 'duplicate script instructions') + + # + # Test contradictory script instructions + # + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <link> + <script>source</script> + <script>source2</script> + </link> + </config> + EOF + end + + File.delete(@targetfile) if File.symlink?(@targetfile) + + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.puts("@contents << '#{@destfile}'") + end + File.open("#{@repodir}/source/#{@targetfile}/source2", 'w') do |file| + file.puts("@contents << '#{@destfile2}'") + end + + # Run etch + #puts "Running contradictory script instructions test" + run_etch(@port, @testbase, true) + + # Verify that the link wasn't created + assert(!File.symlink?(@targetfile) && !File.exist?(@targetfile), 'contradictory script instructions') + end def teardown This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2009-02-06 17:22:41
|
Revision: 64 http://etch.svn.sourceforge.net/etch/?rev=64&view=rev Author: jheiss Date: 2009-02-06 17:22:39 +0000 (Fri, 06 Feb 2009) Log Message: ----------- Add test for multiple attributes. Modified Paths: -------------- trunk/test/attributes.rb Modified: trunk/test/attributes.rb =================================================================== --- trunk/test/attributes.rb 2009-02-06 17:22:19 UTC (rev 63) +++ trunk/test/attributes.rb 2009-02-06 17:22:39 UTC (rev 64) @@ -583,6 +583,37 @@ # Verify that the file was created properly assert_equal(sourcecontents, get_file_contents(@targetfile), testname) + # + # Multiple fact comparison + # + testname = 'multiple fact comparison' + + FileUtils.mkdir_p("#{@repodir}/source/#{@targetfile}") + File.open("#{@repodir}/source/#{@targetfile}/config.xml", 'w') do |file| + file.puts <<-EOF + <config> + <file> + <warning_file/> + <source> + <plain operatingsystem="#{os}" operatingsystemrelease="#{osrel}">source</plain> + </source> + </file> + </config> + EOF + end + + sourcecontents = "Test #{testname}\n" + File.open("#{@repodir}/source/#{@targetfile}/source", 'w') do |file| + file.write(sourcecontents) + end + + # Run etch + #puts "Running '#{testname}' test" + run_etch(@port, @testbase) + + # Verify that the file was created properly + assert_equal(sourcecontents, get_file_contents(@targetfile), testname) + end def teardown This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2009-02-06 17:22:22
|
Revision: 63 http://etch.svn.sourceforge.net/etch/?rev=63&view=rev Author: jheiss Date: 2009-02-06 17:22:19 +0000 (Fri, 06 Feb 2009) Log Message: ----------- Fix up the way in which debug is activated. Previously it changed the variable that was passed to us, possibly messing up the caller if it used that variable again later. Modified Paths: -------------- trunk/test/etchtest.rb Modified: trunk/test/etchtest.rb =================================================================== --- trunk/test/etchtest.rb 2009-02-06 17:20:51 UTC (rev 62) +++ trunk/test/etchtest.rb 2009-02-06 17:22:19 UTC (rev 63) @@ -54,6 +54,7 @@ sleep(5) else Dir.chdir('../server/trunk') + #Dir.chdir('../server/branches/libxml') # Causes ruby to fork, so we're left with a useless pid #exec("./script/server -d -p #{port}") # Causes ruby to invoke a copy of sh to run the command (to handle @@ -70,7 +71,7 @@ end def run_etch(port, testbase, errors_expected=false, extra_args='') - #extra_args << " --debug" + #extra_args = extra_args + " --debug" if errors_expected # Warn the user that errors are expected. Otherwise it can be # disconcerting if you're watching the tests run and see errors. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2009-02-06 17:20:53
|
Revision: 62 http://etch.svn.sourceforge.net/etch/?rev=62&view=rev Author: jheiss Date: 2009-02-06 17:20:51 +0000 (Fri, 06 Feb 2009) Log Message: ----------- Add the allow_nonexistent_dest element. Added that feature to etch a while ago but forgot to update the DTD. Modified Paths: -------------- trunk/etchserver-demo/config.dtd trunk/etchserver-samples/config.dtd Modified: trunk/etchserver-demo/config.dtd =================================================================== --- trunk/etchserver-demo/config.dtd 2009-02-06 17:19:54 UTC (rev 61) +++ trunk/etchserver-demo/config.dtd 2009-02-06 17:20:51 UTC (rev 62) @@ -28,7 +28,8 @@ <!ELEMENT template (#PCDATA)> <!ELEMENT script (#PCDATA)> -<!ELEMENT link (owner?, group?, perms?, overwrite_directory?, (dest|script)*)> +<!ELEMENT link (owner?, group?, perms?, allow_nonexistent_dest?, overwrite_directory?, (dest|script)*)> +<!ELEMENT allow_nonexistent_dest EMPTY> <!ELEMENT dest (#PCDATA)> <!ELEMENT directory (owner?, group?, perms?, (create|script)*)> Modified: trunk/etchserver-samples/config.dtd =================================================================== --- trunk/etchserver-samples/config.dtd 2009-02-06 17:19:54 UTC (rev 61) +++ trunk/etchserver-samples/config.dtd 2009-02-06 17:20:51 UTC (rev 62) @@ -28,7 +28,8 @@ <!ELEMENT template (#PCDATA)> <!ELEMENT script (#PCDATA)> -<!ELEMENT link (owner?, group?, perms?, overwrite_directory?, (dest|script)*)> +<!ELEMENT link (owner?, group?, perms?, allow_nonexistent_dest?, overwrite_directory?, (dest|script)*)> +<!ELEMENT allow_nonexistent_dest EMPTY> <!ELEMENT dest (#PCDATA)> <!ELEMENT directory (owner?, group?, perms?, (create|script)*)> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2009-02-06 17:19:57
|
Revision: 61 http://etch.svn.sourceforge.net/etch/?rev=61&view=rev Author: jheiss Date: 2009-02-06 17:19:54 +0000 (Fri, 06 Feb 2009) Log Message: ----------- Add config.dtd to the test repository Added Paths: ----------- trunk/test/testrepo/config.dtd Added: trunk/test/testrepo/config.dtd =================================================================== --- trunk/test/testrepo/config.dtd (rev 0) +++ trunk/test/testrepo/config.dtd 2009-02-06 17:19:54 UTC (rev 61) @@ -0,0 +1,48 @@ +<!ELEMENT config (revert?, depend*, server_setup?, setup?, pre?, (file|link|directory|delete)+, test_before_post?, post?, test?)> + +<!ELEMENT revert EMPTY> + +<!ELEMENT depend (#PCDATA)> + +<!ELEMENT server_setup (exec*)> +<!ELEMENT setup (exec*)> +<!ELEMENT exec (#PCDATA)> + +<!ELEMENT pre (exec*)> + +<!ELEMENT file (owner?, group?, perms?, always_manage_metadata?, warning_file?, warning_on_second_line?, no_space_around_warning?, comment_open?, comment_line?, comment_close?, allow_empty?, overwrite_directory?, source?)> +<!ELEMENT owner (#PCDATA)> +<!ELEMENT group (#PCDATA)> +<!ELEMENT perms (#PCDATA)> +<!ELEMENT always_manage_metadata EMPTY> +<!ELEMENT warning_file (#PCDATA)> +<!ELEMENT warning_on_second_line EMPTY> +<!ELEMENT no_space_around_warning EMPTY> +<!ELEMENT comment_open (#PCDATA)> +<!ELEMENT comment_line (#PCDATA)> +<!ELEMENT comment_close (#PCDATA)> +<!ELEMENT allow_empty EMPTY> +<!ELEMENT overwrite_directory EMPTY> +<!ELEMENT source (plain|template|script)*> +<!ELEMENT plain (#PCDATA)> +<!ELEMENT template (#PCDATA)> +<!ELEMENT script (#PCDATA)> + +<!ELEMENT link (owner?, group?, perms?, allow_nonexistent_dest?, overwrite_directory?, (dest|script)*)> +<!ELEMENT allow_nonexistent_dest EMPTY> +<!ELEMENT dest (#PCDATA)> + +<!ELEMENT directory (owner?, group?, perms?, (create|script)*)> +<!ELEMENT create EMPTY> + +<!ELEMENT delete (overwrite_directory?, (proceed|script)*)> +<!ELEMENT proceed EMPTY> + +<!ELEMENT test_before_post (exec*)> + +<!ELEMENT post (exec_once*, exec_once_per_run*, exec*)> +<!ELEMENT exec_once (#PCDATA)> +<!ELEMENT exec_once_per_run (#PCDATA)> + +<!ELEMENT test (exec*)> + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <jh...@us...> - 2009-01-06 00:13:36
|
Revision: 60 http://etch.svn.sourceforge.net/etch/?rev=60&view=rev Author: jheiss Date: 2009-01-06 00:13:34 +0000 (Tue, 06 Jan 2009) Log Message: ----------- Tag 3.4 release Modified Paths: -------------- Makefile Added Paths: ----------- tags/release-3.4/ Modified: Makefile =================================================================== --- Makefile 2009-01-06 00:02:17 UTC (rev 59) +++ Makefile 2009-01-06 00:13:34 UTC (rev 60) @@ -1,4 +1,4 @@ -VER=3.3 +VER=3.4 TAGNAME=release-$(VER) # Perhaps somewith with better make skill than I've got can make this This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Jason H. <jh...@ap...> - 2009-01-06 00:07:36
|
Finally looked up how to turn on svn commit emails on sourceforge, so they will now be sent to the etch-devel list. Jason |
From: <jh...@us...> - 2009-01-06 00:02:19
|
Revision: 59 http://etch.svn.sourceforge.net/etch/?rev=59&view=rev Author: jheiss Date: 2009-01-06 00:02:17 +0000 (Tue, 06 Jan 2009) Log Message: ----------- Add output/status capturing, and reporting to the server. In the process implemented the "skip" option in interactive mode. Modified Paths: -------------- trunk/client/etch.rb Modified: trunk/client/etch.rb =================================================================== --- trunk/client/etch.rb 2009-01-05 23:49:19 UTC (rev 58) +++ trunk/client/etch.rb 2009-01-06 00:02:17 UTC (rev 59) @@ -6,6 +6,7 @@ require 'find' require 'digest/sha1' # hexdigest require 'base64' # decode64, encode64 +require 'uri' require 'net/http' require 'net/https' require 'rexml/document' @@ -31,9 +32,13 @@ CONFIRM_PROCEED = 1 CONFIRM_SKIP = 2 CONFIRM_QUIT = 3 - + + # We need these in relation to the output capturing + ORIG_STDOUT = STDOUT.dup + ORIG_STDERR = STDERR.dup + attr_reader :exec_once_per_run - + # Cutting down the size of the arg list would be nice def initialize(server=nil, tag=nil, varbase=nil, debug=false, dryrun=false, interactive=false, filenameonly=false, fullfile=false) @server = server.nil? ? 'https://etch' : server @@ -49,14 +54,17 @@ # cron. # FIXME: Read from config file ENV['PATH'] = '/bin:/usr/bin:/sbin:/usr/sbin:/opt/csw/bin:/opt/csw/sbin' - + + @filesuri = URI.parse(@server + '/files') + @resultsuri = URI.parse(@server + '/results') + @origbase = File.join(@varbase, 'orig') @historybase = File.join(@varbase, 'history') @lockbase = File.join(@varbase, 'locks') @blankrequest = {} - facts = Facter.to_hash - facts.each_pair { |key, value| @blankrequest["facts[#{key}]"] = value.to_s } + @facts = Facter.to_hash + @facts.each_pair { |key, value| @blankrequest["facts[#{key}]"] = value.to_s } if @debug @blankrequest['debug'] = '1' end @@ -69,37 +77,23 @@ @already_processed = {} @exec_already_processed = {} @exec_once_per_run = {} + @results = [] + # See start/stop_output_capture for these + @output_pipes = [] @lchown_supported = nil @lchmod_supported = nil end def process_until_done(files_to_generate, disableforce, lockforce) - check_for_disable_etch_file(disableforce) - remove_stale_lock_files(lockforce) - - # Assemble the initial request - request = get_blank_request - - if !files_to_generate.nil? && !files_to_generate.empty? - files_to_generate.each do |file| - request["files[#{CGI.escape(file)}][sha1sum]"] = get_orig_sum(file) - end - else - request['files[GENERATEALL]'] = '1' - end - - # - # Loop back and forth with the server sending requests for files and - # responding to the server's requests for original contents or sums - # it needs - # - - Signal.trap('EXIT') { unlock_all_files } - - uri = URI.parse(@server + '/files') - http = Net::HTTP.new(uri.host, uri.port) - if uri.scheme == "https" + # Our overall status. Will be reported to the server and used as the + # return value for this method. Command-line clients should use it as + # their exit value. Zero indicates no errors. + status = 0 + message = '' + + http = Net::HTTP.new(@filesuri.host, @filesuri.port) + if @filesuri.scheme == "https" http.use_ssl = true if File.exist?('/etc/etch/ca.pem') http.ca_file = '/etc/etch/ca.pem' @@ -110,943 +104,1077 @@ end end http.start + + # catch/throw for expected/non-error events that end processing + # begin/raise for error events that end processing + catch :stop_processing do + begin + enabled, message = check_for_disable_etch_file(disableforce) + if !enabled + # 200 is the arbitrarily picked exit value indicating + # that etch is disabled + status = 200 + throw :stop_processing + end + remove_stale_lock_files(lockforce) - 10.times do - # - # Send request to server - # + # Assemble the initial request + request = get_blank_request - puts "Sending request to server #{uri}" if (@debug) - post = Net::HTTP::Post.new(uri.path) - post.set_form_data(request) - response = http.request(post) - response_xml = nil - case response - when Net::HTTPSuccess - puts "Response from server:\n'#{response.body}'" if (@debug) - if !response.body.nil? && !response.body.empty? - response_xml = REXML::Document.new(response.body) + if !files_to_generate.nil? && !files_to_generate.empty? + files_to_generate.each do |file| + request["files[#{CGI.escape(file)}][sha1sum]"] = get_orig_sum(file) + end else - puts " Response is empty" if (@debug) - break + request['files[GENERATEALL]'] = '1' end - else - puts response.body - # error! raises an exception - response.error! - end - # - # Process the response from the server - # + # + # Loop back and forth with the server sending requests for files and + # responding to the server's requests for original contents or sums + # it needs + # + + Signal.trap('EXIT') do + STDOUT.reopen(ORIG_STDOUT) + STDERR.reopen(ORIG_STDERR) + unlock_all_files + end + + 10.times do + # + # Send request to server + # + + puts "Sending request to server #{@filesuri}" if (@debug) + post = Net::HTTP::Post.new(@filesuri.path) + post.set_form_data(request) + response = http.request(post) + response_xml = nil + case response + when Net::HTTPSuccess + puts "Response from server:\n'#{response.body}'" if (@debug) + if !response.body.nil? && !response.body.empty? + response_xml = REXML::Document.new(response.body) + else + puts " Response is empty" if (@debug) + break + end + else + $stderr.puts response.body + # error! raises an exception + response.error! + end - # Prep a clean request hash - request = get_blank_request + # + # Process the response from the server + # - # With generateall we expect to make at least two round trips to the server. - # 1) Send GENERATEALL request, get back a list of need_sums - # 2) Send sums, possibly get back some need_origs - # 3) Send origs, get back generated files - need_to_loop = false - reset_already_processed - # Process configs first, as they may contain setup entries that are - # needed to create the original files. - response_xml.root.elements.each('/files/configs/config') do |config| - puts "Processing config for #{config.attributes['filename']}" if (@debug) - process(response_xml, config.attributes['filename']) + # Prep a clean request hash + request = get_blank_request + + # With generateall we expect to make at least two round trips to the server. + # 1) Send GENERATEALL request, get back a list of need_sums + # 2) Send sums, possibly get back some need_origs + # 3) Send origs, get back generated files + need_to_loop = false + reset_already_processed + # Process configs first, as they may contain setup entries that are + # needed to create the original files. + response_xml.root.elements.each('/files/configs/config') do |config| + file = config.attributes['filename'] + puts "Processing config for #{file}" if (@debug) + continue_processing = process(response_xml, file) + if !continue_processing + throw :stop_processing + end + end + response_xml.root.elements.each('/files/need_sums/need_sum') do |need_sum| + puts "Processing request for sum of #{need_sum.text}" if (@debug) + request["files[#{CGI.escape(need_sum.text)}][sha1sum]"] = get_orig_sum(need_sum.text) + need_to_loop = true + end + response_xml.root.elements.each('/files/need_origs/need_orig') do |need_orig| + puts "Processing request for contents of #{need_orig.text}" if (@debug) + request["files[#{CGI.escape(need_orig.text)}][contents]"] = Base64.encode64(get_orig_contents(need_orig.text)) + request["files[#{CGI.escape(need_orig.text)}][sha1sum]"] = get_orig_sum(need_orig.text) + need_to_loop = true + end + + if !need_to_loop + break + end + end + + puts "Processing 'exec once per run' commands" if (!exec_once_per_run.empty?) + exec_once_per_run.keys.each do |exec| + process_exec('post', exec) + end + rescue Exception => e + status = 1 + $stderr.puts e.message + $stderr.puts e.backtrace.join("\n") if @debug + end # begin/rescue + end # catch + + # Send results to server + if !@dryrun + rails_results = [] + # CGI.escape doesn't work on things that aren't strings, so we don't + # call it on a few of the fields here that are numbers or booleans + rails_results << "fqdn=#{CGI.escape(@facts['fqdn'])}" + rails_results << "status=#{status}" + rails_results << "message=#{CGI.escape(message)}" + @results.each do |result| + # Strangely enough this works. Even though the key is not unique to + # each result the Rails parameter parsing code keeps track of keys it + # has seen, and if it sees a duplicate it starts a new hash. + rails_results << "results[][file]=#{CGI.escape(result['file'])}" + rails_results << "results[][success]=#{result['success']}" + rails_results << "results[][message]=#{CGI.escape(result['message'])}" end - response_xml.root.elements.each('/files/need_sums/need_sum') do |need_sum| - puts "Processing request for sum of #{need_sum.text}" if (@debug) - request["files[#{CGI.escape(need_sum.text)}][sha1sum]"] = get_orig_sum(need_sum.text) - need_to_loop = true + puts "Sending results to server #{@resultsuri}" if (@debug) + resultspost = Net::HTTP::Post.new(@resultsuri.path) + # We have to bypass Net::HTTP's set_form_data method in this case + # because it expects a hash and we can't provide the results in the + # format we want in a hash because we'd have duplicate keys (see above). + resultspost.body = rails_results.join('&') + resultspost.content_type = 'application/x-www-form-urlencoded' + response = http.request(resultspost) + case response + when Net::HTTPSuccess + puts "Response from server:\n'#{response.body}'" if (@debug) + else + $stderr.puts "Error submitting results:" + $stderr.puts response.body end - response_xml.root.elements.each('/files/need_origs/need_orig') do |need_orig| - puts "Processing request for contents of #{need_orig.text}" if (@debug) - request["files[#{CGI.escape(need_orig.text)}][contents]"] = Base64.encode64(get_orig_contents(need_orig.text)) - request["files[#{CGI.escape(need_orig.text)}][sha1sum]"] = get_orig_sum(need_orig.text) - need_to_loop = true - end - - if !need_to_loop - break - end end - - puts "Processing 'exec once per run' commands" if (!exec_once_per_run.empty?) - exec_once_per_run.keys.each do |exec| - process_exec('post', exec) - end - # Send results to server - # FIXME + status end def check_for_disable_etch_file(disableforce) disable_etch = File.join(@varbase, 'disable_etch') + message = '' if File.exist?(disable_etch) if !disableforce - puts "Etch disabled:" - $stdout.write(IO.read(disable_etch)) - exit(200) + message = "Etch disabled:\n" + message << IO.read(disable_etch) + puts message + return false, message else puts "Ignoring disable_etch file" end end + return true, message end def get_blank_request @blankrequest.dup end + # Raises an exception if any fatal error is encountered + # Returns a boolean, true unless the user indicated in interactive mode + # that further processing should be halted def process(response_xml, file) - puts "Processing #{file}" if (@debug) - + continue_processing = true + save_results = true + exception = nil + # Skip files we've already processed in response to <depend> # statements. if @already_processed.has_key?(file) puts "Skipping already processed #{file}" if (@debug) - return + return continue_processing end + + # Prep the results capturing for this file + result = {} + result['file'] = file + result['success'] = true + result['message'] = '' + + # catch/throw for expected/non-error events that end processing + # begin/raise for error events that end processing + # Within this block you should throw :process_done if you've reached + # a natural stopping point and nothing further needs to be done. You + # should raise an exception if you encounter an error condition. + # Do not 'return' or 'abort'. + catch :process_done do + begin + start_output_capture + + puts "Processing #{file}" if (@debug) + + # The %locked_files hash provides a convenient way to + # detect circular dependancies. It doesn't give us an ordered + # list of dependencies, which might be handy to help the user + # debug the problem, but I don't think it's worth maintaining a + # seperate array just for that purpose. + if @locked_files.has_key?(file) + raise "Circular dependancy detected. " + + "Dependancy list (unsorted) contains:\n " + + @locked_files.keys.join(', ') + end - # The %locked_files hash provides a convenient way to - # detect circular dependancies. It doesn't give us an ordered - # list of dependancies, which might be handy to help the user - # debug the problem, but I don't think it's worth maintaining a - # seperate array just for that purpose. - if @locked_files.has_key?(file) - abort "Circular dependancy detected. " + - "Dependancy list (unsorted) contains:\n " + - @locked_files.keys.join(', ') - end + # This needs to be after the circular dependency check + lock_file(file) + + # We have to make a new document so that XPath paths are referenced + # relative to the configuration for this specific file. + config = REXML::Document.new(response_xml.root.elements["/files/configs/config[@filename='#{file}']"].to_s) - lock_file(file) - done = false + # Process any other files that this file depends on + config.elements.each('/config/depend') do |depend| + puts "Generating dependency #{depend.text}" if (@debug) + process(response_xml, depend.text) + end - # We have to make a new document so that XPath paths are referenced - # relative to the configuration for this specific file. - config = REXML::Document.new(response_xml.root.elements["/files/configs/config[@filename='#{file}']"].to_s) + # See what type of action the user has requested - # Process any other files that this file depends on - config.elements.each('/config/depend') do |depend| - puts "Generating dependency #{depend.text}" if (@debug) - process(response_xml, depend.text) - end + # Check to see if the user has requested that we revert back to the + # original file. + if config.elements['/config/revert'] + origpathbase = File.join(@origbase, file) - # See what type of action the user has requested + # Restore the original file if it is around + if File.exist?("#{origpathbase}.ORIG") + origpath = "#{origpathbase}.ORIG" + origdir = File.dirname(origpath) + origbase = File.basename(origpath) + filedir = File.dirname(file) - # Check to see if the user has requested that we revert back to the - # original file. - if config.elements['/config/revert'] - origpathbase = File.join(@origbase, file) + # Remove anything we might have written out for this file + remove_file(file) if (!@dryrun) - # Restore the original file if it is around - if File.exist?("#{origpathbase}.ORIG") - origpath = "#{origpathbase}.ORIG" - origdir = File.dirname(origpath) - origbase = File.basename(origpath) - filedir = File.dirname(file) + puts "Restoring #{origpath} to #{file}" + recursive_copy_and_rename(origdir, origbase, file) if (!@dryrun) - # Remove anything we might have written out for this file - remove_file(file) if (!@dryrun) + # Now remove the backed-up original so that future runs + # don't do anything + remove_file(origpath) if (!@dryrun) + elsif File.exist?("#{origpathbase}.TAR") + origpath = "#{origpathbase}.TAR" + filedir = File.dirname(file) - puts "Restoring #{origpath} to #{file}" - recursive_copy_and_rename(origdir, origbase, file) if (!@dryrun) + # Remove anything we might have written out for this file + remove_file(file) if (!@dryrun) - # Now remove the backed-up original so that future runs - # don't do anything - remove_file(origpath) if (!@dryrun) - elsif File.exist?("#{origpathbase}.TAR") - origpath = "#{origpathbase}.TAR" - filedir = File.dirname(file) + puts "Restoring #{file} from #{origpath}" + system("cd #{filedir} && tar xf #{origpath}") if (!@dryrun) - # Remove anything we might have written out for this file - remove_file(file) if (!@dryrun) + # Now remove the backed-up original so that future runs + # don't do anything + remove_file(origpath) if (!@dryrun) + elsif File.exist?("#{origpathbase}.NOORIG") + origpath = "#{origpathbase}.NOORIG" + puts "Original #{file} didn't exist, restoring that state" - puts "Restoring #{file} from #{origpath}" - system("cd #{filedir} && tar xf #{origpath}") if (!@dryrun) + # Remove anything we might have written out for this file + remove_file(file) if (!@dryrun) - # Now remove the backed-up original so that future runs - # don't do anything - remove_file(origpath) if (!@dryrun) - elsif File.exist?("#{origpathbase}.NOORIG") - origpath = "#{origpathbase}.NOORIG" - puts "Original #{file} didn't exist, restoring that state" + # Now remove the backed-up original so that future runs + # don't do anything + remove_file(origpath) if (!@dryrun) + end - # Remove anything we might have written out for this file - remove_file(file) if (!@dryrun) + throw :process_done + end - # Now remove the backed-up original so that future runs - # don't do anything - remove_file(origpath) if (!@dryrun) - end + # Perform any setup commands that the user has requested. + # These are occasionally needed to install software that is + # required to generate the file (think m4 for sendmail.cf) or to + # install a package containing a sample config file which we + # then edit with a script, and thus doing the install in <pre> + # is too late. + if config.elements['/config/setup'] + process_setup(file, config) + end - done = true - end + if config.elements['/config/file'] # Regular file + newcontents = nil + if config.elements['/config/file/contents'] + newcontents = Base64.decode64(config.elements['/config/file/contents'].text) + end - # Perform any setup commands that the user has requested. - # These are occasionally needed to install software that is - # required to generate the file (think m4 for sendmail.cf) or to - # install a package containing a sample config file which we - # then edit with a script, and thus doing the install in <pre> - # is too late. - if config.elements['/config/setup'] && !done - process_setup(file, config) - end + permstring = config.elements['/config/file/perms'].text + perms = permstring.oct + owner = config.elements['/config/file/owner'].text + group = config.elements['/config/file/group'].text + uid = lookup_uid(owner) + gid = lookup_gid(group) - if config.elements['/config/file'] && !done # Regular file - newcontents = nil - if config.elements['/config/file/contents'] - newcontents = Base64.decode64(config.elements['/config/file/contents'].text) - end + set_file_contents = false + if newcontents + set_file_contents = compare_file_contents(file, newcontents) + end + set_permissions = nil + set_ownership = nil + # If the file is currently something other than a plain file then + # always set the flags to set the permissions and ownership. + # Checking the permissions/ownership of whatever is there currently + # is useless. + if set_file_contents && (!File.file?(file) || File.symlink?(file)) + set_permissions = true + set_ownership = true + else + set_permissions = compare_permissions(file, perms) + set_ownership = compare_ownership(file, uid, gid) + end - permstring = config.elements['/config/file/perms'].text - perms = permstring.oct - owner = config.elements['/config/file/owner'].text - group = config.elements['/config/file/group'].text - uid = lookup_uid(owner) - gid = lookup_gid(group) + # Proceed if: + # - The new contents are different from the current file + # - The permissions or ownership requested don't match the + # current permissions or ownership + if !set_file_contents && + !set_permissions && + !set_ownership + puts "No change to #{file} necessary" if (@debug) + throw :process_done + else + # Tell the user what we're going to do + if set_file_contents + # If the new contents are different from the current file + # show that to the user in the format they've requested. + # If the requested permissions are not world-readable then + # use the filenameonly format so that we don't disclose + # non-public data, unless we're in interactive mode + if @filenameonly || (permstring.to_i(8) & 0004 == 0 && !@interactive) + puts "Will write out new #{file}" + elsif @fullfile + # Grab the first 8k of the contents + first8k = newcontents.slice(0, 8192) + # Then check it for null characters. If it has any it's + # likely a binary file. + hasnulls = true if (first8k =~ /\0/) - set_file_contents = false - if newcontents - set_file_contents = compare_file_contents(file, newcontents) - end - set_permissions = nil - set_ownership = nil - # If the file is currently something other than a plain file then - # always set the flags to set the permissions and ownership. - # Checking the permissions/ownership of whatever is there currently - # is useless. - if set_file_contents && (!File.file?(file) || File.symlink?(file)) - set_permissions = true - set_ownership = true - else - set_permissions = compare_permissions(file, perms) - set_ownership = compare_ownership(file, uid, gid) - end - - # Proceed if: - # - The new contents are different from the current file - # - The permissions or ownership requested don't match the - # current permissions or ownership - if !set_file_contents && - !set_permissions && - !set_ownership - puts "No change to #{file} necessary" if (@debug) - done = true - else - # Tell the user what we're going to do - if set_file_contents - # If the new contents are different from the current file - # show that to the user in the format they've requested. - # If the requested permissions are not world-readable then - # use the filenameonly format so that we don't disclose - # non-public data, unless we're in interactive mode - if @filenameonly || (permstring.to_i(8) & 0004 == 0 && !@interactive) - puts "Will write out new #{file}" - elsif @fullfile - # Grab the first 8k of the contents - first8k = newcontents.slice(0, 8192) - # Then check it for null characters. If it has any it's - # likely a binary file. - hasnulls = true if (first8k =~ /\0/) - - if !hasnulls - puts "Generated contents for #{file}:" - puts "=============================================" - puts newcontents - puts "=============================================" - else - puts "Will write out new #{file}, but " + - "generated contents are not plain text so " + - "they will not be displayed" + if !hasnulls + puts "Generated contents for #{file}:" + puts "=============================================" + puts newcontents + puts "=============================================" + else + puts "Will write out new #{file}, but " + + "generated contents are not plain text so " + + "they will not be displayed" + end + else + # Default is to show a diff of the current file and the + # newly generated file. + puts "Will make the following changes to #{file}, diff -c:" + tempfile = Tempfile.new(File.basename(file)) + tempfile.write(newcontents) + tempfile.close + puts "=============================================" + if File.file?(file) && !File.symlink?(file) + system("diff -c #{file} #{tempfile.path}") + else + # Either the file doesn't currently exist, + # or is something other than a normal file + # that we'll be replacing with a file. In + # either case diffing against /dev/null will + # produce the most logical output. + system("diff -c /dev/null #{tempfile.path}") + end + puts "=============================================" + tempfile.delete + end end - else - # Default is to show a diff of the current file and the - # newly generated file. - puts "Will make the following changes to #{file}, diff -c:" - tempfile = Tempfile.new(File.basename(file)) - tempfile.write(newcontents) - tempfile.close - puts "=============================================" - if File.file?(file) && !File.symlink?(file) - system("diff -c #{file} #{tempfile.path}") - else - # Either the file doesn't currently exist, - # or is something other than a normal file - # that we'll be replacing with a file. In - # either case diffing against /dev/null will - # produce the most logical output. - system("diff -c /dev/null #{tempfile.path}") + if set_permissions + puts "Will set permissions on #{file} to #{permstring}" end - puts "=============================================" - tempfile.delete - end - end - if set_permissions - puts "Will set permissions on #{file} to #{permstring}" - end - if set_ownership - puts "Will set ownership of #{file} to #{uid}:#{gid}" - end + if set_ownership + puts "Will set ownership of #{file} to #{uid}:#{gid}" + end - # If the user requested interactive mode ask them for - # confirmation to proceed. - if @interactive - case get_user_confirmation() - when CONFIRM_PROCEED - # No need to do anything - when CONFIRM_SKIP - # FIXME - abort - when CONFIRM_QUIT - unlock_all_files - exit - else - abort "Unexpected result from get_user_confirmation()" - end - end + # If the user requested interactive mode ask them for + # confirmation to proceed. + if @interactive + case get_user_confirmation() + when CONFIRM_PROCEED + # No need to do anything + when CONFIRM_SKIP + save_results = false + throw :process_done + when CONFIRM_QUIT + unlock_all_files + continue_processing = false + save_results = false + throw :process_done + else + raise "Unexpected result from get_user_confirmation()" + end + end - # Perform any pre-action commands that the user has requested - if config.elements['/config/pre'] - process_pre(file, config) - end + # Perform any pre-action commands that the user has requested + if config.elements['/config/pre'] + process_pre(file, config) + end - # If the original "file" is a directory and the user hasn't - # specifically told us we can overwrite it then abort. - # - # The test is here, rather than a bit earlier where you might - # expect it, because the pre section may be used to address - # originals which are directories. So we don't check until - # after any pre commands are run. - if File.directory?(file) && !File.symlink?(file) && - !config.elements['/config/file/overwrite_directory'] - abort "Can't proceed, original of #{file} is a directory,\n" + - " consider the overwrite_directory flag if appropriate." - end + # If the original "file" is a directory and the user hasn't + # specifically told us we can overwrite it then raise an exception. + # + # The test is here, rather than a bit earlier where you might + # expect it, because the pre section may be used to address + # originals which are directories. So we don't check until + # after any pre commands are run. + if File.directory?(file) && !File.symlink?(file) && + !config.elements['/config/file/overwrite_directory'] + raise "Can't proceed, original of #{file} is a directory,\n" + + " consider the overwrite_directory flag if appropriate." + end - # Give save_orig a definitive answer on whether or not to save the - # contents of an original directory. - origpath = save_orig(file, true) - # Update the history log - save_history(file) + # Give save_orig a definitive answer on whether or not to save the + # contents of an original directory. + origpath = save_orig(file, true) + # Update the history log + save_history(file) - # Make a backup in case we need to roll back. We have no use - # for a backup if there are no test commands defined (since we - # only use the backup to roll back if the test fails), so don't - # bother to create a backup unless there is a test command defined. - backup = nil - if config.elements['/config/test_before_post'] || - config.elements['/config/test'] - backup = make_backup(file) - puts "Created backup #{backup}" - end + # Make a backup in case we need to roll back. We have no use + # for a backup if there are no test commands defined (since we + # only use the backup to roll back if the test fails), so don't + # bother to create a backup unless there is a test command defined. + backup = nil + if config.elements['/config/test_before_post'] || + config.elements['/config/test'] + backup = make_backup(file) + puts "Created backup #{backup}" + end - # Make sure the directory tree for this file exists - filedir = File.dirname(file) - if !File.directory?(filedir) - puts "Making directory tree #{filedir}" - FileUtils.mkpath(filedir) if (!@dryrun) - end - - # If the new contents are different from the current file, - # replace the file. - if set_file_contents - if !@dryrun - # Write out the new contents into a temporary file - filebase = File.basename(file) + # Make sure the directory tree for this file exists filedir = File.dirname(file) - newfile = Tempfile.new(filebase, filedir) - - # Set the proper permissions on the file before putting - # data into it. - newfile.chmod(perms) - begin - newfile.chown(uid, gid) - rescue Errno::EPERM - raise if Process.euid == 0 + if !File.directory?(filedir) + puts "Making directory tree #{filedir}" + FileUtils.mkpath(filedir) if (!@dryrun) end - puts "Writing new contents of #{file} to #{newfile.path}" if (@debug) - newfile.write(newcontents) - newfile.close + # If the new contents are different from the current file, + # replace the file. + if set_file_contents + if !@dryrun + # Write out the new contents into a temporary file + filebase = File.basename(file) + filedir = File.dirname(file) + newfile = Tempfile.new(filebase, filedir) - # If the current file is not a plain file, remove it. - # Plain files are left alone so that the replacement is - # atomic. - if File.symlink?(file) || (File.exist?(file) && ! File.file?(file)) - puts "Current #{file} is not a plain file, removing it" if (@debug) - remove_file(file) - end + # Set the proper permissions on the file before putting + # data into it. + newfile.chmod(perms) + begin + newfile.chown(uid, gid) + rescue Errno::EPERM + raise if Process.euid == 0 + end - # Move the new file into place - File.rename(newfile.path, file) - - # Check the permissions and ownership now to ensure they - # end up set properly - set_permissions = compare_permissions(file, perms) - set_ownership = compare_ownership(file, uid, gid) - end - end + puts "Writing new contents of #{file} to #{newfile.path}" if (@debug) + newfile.write(newcontents) + newfile.close - # Ensure the permissions are set properly - if set_permissions - File.chmod(perms, file) if (!@dryrun) - end + # If the current file is not a plain file, remove it. + # Plain files are left alone so that the replacement is + # atomic. + if File.symlink?(file) || (File.exist?(file) && ! File.file?(file)) + puts "Current #{file} is not a plain file, removing it" if (@debug) + remove_file(file) + end - # Ensure the ownership is set properly - if set_ownership - begin - File.chown(uid, gid, file) if (!@dryrun) - rescue Errno::EPERM - raise if Process.euid == 0 - end - end + # Move the new file into place + File.rename(newfile.path, file) + + # Check the permissions and ownership now to ensure they + # end up set properly + set_permissions = compare_permissions(file, perms) + set_ownership = compare_ownership(file, uid, gid) + end + end - # Perform any test_before_post commands that the user has requested - if config.elements['/config/test_before_post'] - if !process_test_before_post(file, config) - restore_backup(file, backup) - return - end - end + # Ensure the permissions are set properly + if set_permissions + File.chmod(perms, file) if (!@dryrun) + end - # Perform any post-action commands that the user has requested - if config.elements['/config/post'] - process_post(file, config) - end + # Ensure the ownership is set properly + if set_ownership + begin + File.chown(uid, gid, file) if (!@dryrun) + rescue Errno::EPERM + raise if Process.euid == 0 + end + end - # Perform any test commands that the user has requested - if config.elements['/config/test'] - if !process_test(file, config) - restore_backup(file, backup) + # Perform any test_before_post commands that the user has requested + if config.elements['/config/test_before_post'] + if !process_test_before_post(file, config) + restore_backup(file, backup) + raise "test_before_post failed" + end + end - # Re-run any post commands + # Perform any post-action commands that the user has requested if config.elements['/config/post'] process_post(file, config) end - end - end - # Clean up the backup, we don't need it anymore - if config.elements['/config/test_before_post'] || - config.elements['/config/test'] - puts "Removing backup #{backup}" - remove_file(backup) if (!@dryrun); - end + # Perform any test commands that the user has requested + if config.elements['/config/test'] + if !process_test(file, config) + restore_backup(file, backup) - # Update the history log again - save_history(file) + # Re-run any post commands + if config.elements['/config/post'] + process_post(file, config) + end + end + end - done = true - end - end + # Clean up the backup, we don't need it anymore + if config.elements['/config/test_before_post'] || + config.elements['/config/test'] + puts "Removing backup #{backup}" + remove_file(backup) if (!@dryrun); + end - if config.elements['/config/link'] && !done # Symbolic link + # Update the history log again + save_history(file) - dest = config.elements['/config/link/dest'].text + throw :process_done + end + end - set_link_destination = compare_link_destination(file, dest) - absdest = File.expand_path(dest, File.dirname(file)) + if config.elements['/config/link'] # Symbolic link - permstring = config.elements['/config/link/perms'].text - perms = permstring.oct - owner = config.elements['/config/link/owner'].text - group = config.elements['/config/link/group'].text - uid = lookup_uid(owner) - gid = lookup_gid(group) - - # lchown and lchmod are not supported on many platforms. The server - # always includes ownership and permissions settings with any link - # (pulling them from defaults.xml if the user didn't specify them in - # the config.xml file.) As such link management would always fail - # on systems which don't support lchown/lchmod, which seems like bad - # behavior. So instead we check to see if they are implemented, and - # if not just ignore ownership/permissions settings. I suppose the - # ideal would be for the server to tell the client whether the - # ownership/permissions were specifically requested (in config.xml) - # rather than just defaults, and then for the client to always try to - # manage ownership/permissions if the settings are not defaults (and - # fail in the event that they aren't implemented.) - if @lchown_supported.nil? - lchowntestlink = Tempfile.new('etchlchowntest').path - lchowntestfile = Tempfile.new('etchlchowntest').path - File.delete(lchowntestlink) - File.symlink(lchowntestfile, lchowntestlink) - begin - File.lchown(0, 0, lchowntestfile) - @lchown_supported = true - rescue NotImplementedError - @lchown_supported = false - rescue Errno::EPERM - raise if Process.euid == 0 - end - end - if @lchmod_supported.nil? - lchmodtestlink = Tempfile.new('etchlchmodtest').path - lchmodtestfile = Tempfile.new('etchlchmodtest').path - File.delete(lchmodtestlink) - File.symlink(lchmodtestfile, lchmodtestlink) - begin - File.lchmod(0644, lchmodtestfile) - @lchmod_supported = true - rescue NotImplementedError - @lchmod_supported = false - end - end - - set_permissions = false - if @lchmod_supported - # If the file is currently something other than a link then - # always set the flags to set the permissions and ownership. - # Checking the permissions/ownership of whatever is there currently - # is useless. - if set_link_destination && !File.symlink?(file) - set_permissions = true - else - set_permissions = compare_permissions(file, perms) - end - end - set_ownership = false - if @lchown_supported - if set_link_destination && !File.symlink?(file) - set_ownership = true - else - set_ownership = compare_ownership(file, uid, gid) - end - end + dest = config.elements['/config/link/dest'].text - # Proceed if: - # - The new link destination differs from the current one - # - The permissions or ownership requested don't match the - # current permissions or ownership - if !set_link_destination && - !set_permissions && - !set_ownership - puts "No change to #{file} necessary" if (@debug) - done = true - # Check that the link destination exists, and refuse to create - # the link unless it does exist or the user told us to go ahead - # anyway. - # - # Note that the destination may be a relative path, and the - # target directory may not exist yet, so we have to convert the - # destination to an absolute path and test that for existence. - # expand_path should handle paths that are already absolute - # properly. - elsif ! File.exist?(absdest) && ! File.symlink?(absdest) && - ! config.elements['/config/link/allow_nonexistent_dest'] - puts "Destination #{dest} for link #{file} does not exist," + - " consider the allow_nonexistent_dest flag if appropriate." - done = true - else - # Tell the user what we're going to do - if set_link_destination - puts "Linking #{file} -> #{dest}" - end - if set_permissions - puts "Will set permissions on #{file} to #{permstring}" - end - if set_ownership - puts "Will set ownership of #{file} to #{uid}:#{gid}" - end + set_link_destination = compare_link_destination(file, dest) + absdest = File.expand_path(dest, File.dirname(file)) - # If the user requested interactive mode ask them for - # confirmation to proceed. - if @interactive - case get_user_confirmation() - when CONFIRM_PROCEED - # No need to do anything - when CONFIRM_SKIP - # FIXME - abort - when CONFIRM_QUIT - unlock_all_files - exit - else - abort "Unexpected result from get_user_confirmation()" + permstring = config.elements['/config/link/perms'].text + perms = permstring.oct + owner = config.elements['/config/link/owner'].text + group = config.elements['/config/link/group'].text + uid = lookup_uid(owner) + gid = lookup_gid(group) + + # lchown and lchmod are not supported on many platforms. The server + # always includes ownership and permissions settings with any link + # (pulling them from defaults.xml if the user didn't specify them in + # the config.xml file.) As such link management would always fail + # on systems which don't support lchown/lchmod, which seems like bad + # behavior. So instead we check to see if they are implemented, and + # if not just ignore ownership/permissions settings. I suppose the + # ideal would be for the server to tell the client whether the + # ownership/permissions were specifically requested (in config.xml) + # rather than just defaults, and then for the client to always try to + # manage ownership/permissions if the settings are not defaults (and + # fail in the event that they aren't implemented.) + if @lchown_supported.nil? + lchowntestlink = Tempfile.new('etchlchowntest').path + lchowntestfile = Tempfile.new('etchlchowntest').path + File.delete(lchowntestlink) + File.symlink(lchowntestfile, lchowntestlink) + begin + File.lchown(0, 0, lchowntestfile) + @lchown_supported = true + rescue NotImplementedError + @lchown_supported = false + rescue Errno::EPERM + raise if Process.euid == 0 + end end - end + if @lchmod_supported.nil? + lchmodtestlink = Tempfile.new('etchlchmodtest').path + lchmodtestfile = Tempfile.new('etchlchmodtest').path + File.delete(lchmodtestlink) + File.symlink(lchmodtestfile, lchmodtestlink) + begin + File.lchmod(0644, lchmodtestfile) + @lchmod_supported = true + rescue NotImplementedError + @lchmod_supported = false + end + end + + set_permissions = false + if @lchmod_supported + # If the file is currently something other than a link then + # always set the flags to set the permissions and ownership. + # Checking the permissions/ownership of whatever is there currently + # is useless. + if set_link_destination && !File.symlink?(file) + set_permissions = true + else + set_permissions = compare_permissions(file, perms) + end + end + set_ownership = false + if @lchown_supported + if set_link_destination && !File.symlink?(file) + set_ownership = true + else + set_ownership = compare_ownership(file, uid, gid) + end + end - # Perform any pre-action commands that the user has requested - if config.elements['/config/pre'] - process_pre(file, config) - end + # Proceed if: + # - The new link destination differs from the current one + # - The permissions or ownership requested don't match the + # current permissions or ownership + if !set_link_destination && + !set_permissions && + !set_ownership + puts "No change to #{file} necessary" if (@debug) + throw :process_done + # Check that the link destination exists, and refuse to create + # the link unless it does exist or the user told us to go ahead + # anyway. + # + # Note that the destination may be a relative path, and the + # target directory may not exist yet, so we have to convert the + # destination to an absolute path and test that for existence. + # expand_path should handle paths that are already absolute + # properly. + elsif ! File.exist?(absdest) && ! File.symlink?(absdest) && + ! config.elements['/config/link/allow_nonexistent_dest'] + puts "Destination #{dest} for link #{file} does not exist," + + " consider the allow_nonexistent_dest flag if appropriate." + throw :process_done + else + # Tell the user what we're going to do + if set_link_destination + puts "Linking #{file} -> #{dest}" + end + if set_permissions + puts "Will set permissions on #{file} to #{permstring}" + end + if set_ownership + puts "Will set ownership of #{file} to #{uid}:#{gid}" + end - # If the original "file" is a directory and the user hasn't - # specifically told us we can overwrite it then abort. - # - # The test is here, rather than a bit earlier where you might - # expect it, because the pre section may be used to address - # originals which are directories. So we don't check until - # after any pre commands are run. - if File.directory?(file) && !File.symlink?(file) && - !config.elements['/config/link/overwrite_directory'] - abort "Can't proceed, original of #{file} is a directory,\n" + - " consider the overwrite_directory flag if appropriate." - end + # If the user requested interactive mode ask them for + # confirmation to proceed. + if @interactive + case get_user_confirmation() + when CONFIRM_PROCEED + # No need to do anything + when CONFIRM_SKIP + save_results = false + throw :process_done + when CONFIRM_QUIT + unlock_all_files + continue_processing = false + save_results = false + throw :process_done + else + raise "Unexpected result from get_user_confirmation()" + end + end - # Give save_orig a definitive answer on whether or not to save the - # contents of an original directory. - origpath = save_orig(file, true) - # Update the history log - save_history(file) + # Perform any pre-action commands that the user has requested + if config.elements['/config/pre'] + process_pre(file, config) + end - # Make a backup in case we need to roll back. We have no use - # for a backup if there are no test commands defined (since we - # only use the backup to roll back if the test fails), so don't - # bother to create a backup unless there is a test command defined. - backup = nil - if config.elements['/config/test_before_post'] || - config.elements['/config/test'] - backup = make_backup(file) - puts "Created backup #{backup}" - end + # If the original "file" is a directory and the user hasn't + # specifically told us we can overwrite it then raise an exception. + # + # The test is here, rather than a bit earlier where you might + # expect it, because the pre section may be used to address + # originals which are directories. So we don't check until + # after any pre commands are run. + if File.directory?(file) && !File.symlink?(file) && + !config.elements['/config/link/overwrite_directory'] + raise "Can't proceed, original of #{file} is a directory,\n" + + " consider the overwrite_directory flag if appropriate." + end - # Make sure the directory tree for this link exists - filedir = File.dirname(file) - if !File.directory?(filedir) - puts "Making directory tree #{filedir}" - FileUtils.mkpath(filedir) if (!@dryrun) - end + # Give save_orig a definitive answer on whether or not to save the + # contents of an original directory. + origpath = save_orig(file, true) + # Update the history log + save_history(file) - # Create the link - if set_link_destination - remove_file(file) if (!@dryrun) - File.symlink(dest, file) if (!@dryrun) + # Make a backup in case we need to roll back. We have no use + # for a backup if there are no test commands defined (since we + # only use the backup to roll back if the test fails), so don't + # bother to create a backup unless there is a test command defined. + backup = nil + if config.elements['/config/test_before_post'] || + config.elements['/config/test'] + backup = make_backup(file) + puts "Created backup #{backup}" + end - # Check the permissions and ownership now to ensure they - # end up set properly - if @lchmod_supported - set_permissions = compare_permissions(file, perms) - end - if @lchown_supported - set_ownership = compare_ownership(file, uid, gid) - end - end + # Make sure the directory tree for this link exists + filedir = File.dirname(file) + if !File.directory?(filedir) + puts "Making directory tree #{filedir}" + FileUtils.mkpath(filedir) if (!@dryrun) + end - # Ensure the permissions are set properly - if set_permissions - # Note: lchmod - File.lchmod(perms, file) if (!@dryrun) - end + # Create the link + if set_link_destination + remove_file(file) if (!@dryrun) + File.symlink(dest, file) if (!@dryrun) - # Ensure the ownership is set properly - if set_ownership - begin - # Note: lchown - File.lchown(uid, gid, file) if (!@dryrun) - rescue Errno::EPERM - raise if Process.euid == 0 - end - end + # Check the permissions and ownership now to ensure they + # end up set properly + if @lchmod_supported + set_permissions = compare_permissions(file, perms) + end + if @lchown_supported + set_ownership = compare_ownership(file, uid, gid) + end + end - # Perform any test_before_post commands that the user has requested - if config.elements['/config/test_before_post'] - if !process_test_before_post(file, config) - restore_backup(file, backup) - return - end - end + # Ensure the permissions are set properly + if set_permissions + # Note: lchmod + File.lchmod(perms, file) if (!@dryrun) + end - # Perform any post-action commands that the user has requested - if config.elements['/config/post'] - process_post(file, config) - end + # Ensure the ownership is set properly + if set_ownership + begin + # Note: lchown + File.lchown(uid, gid, file) if (!@dryrun) + rescue Errno::EPERM + raise if Process.euid == 0 + end + end - # Perform any test commands that the user has requested - if config.elements['/config/test'] - if !process_test(file, config) - restore_backup(file, backup) + # Perform any test_before_post commands that the user has requested + if config.elements['/config/test_before_post'] + if !process_test_before_post(file, config) + restore_backup(file, backup) + raise "test_before_post failed" + end + end - # Re-run any post commands + # Perform any post-action commands that the user has requested if config.elements['/config/post'] process_post(file, config) end - end - end - # Clean up the backup, we don't need it anymore - if config.elements['/config/test_before_post'] || - config.elements['/config/test'] - puts "Removing backup #{backup}" - remove_file(backup) if (!@dryrun); - end + # Perform any test commands that the user has requested + if config.elements['/config/test'] + if !process_test(file, config) + restore_backup(file, backup) - # Update the history log again - save_history(file) + # Re-run any post commands + if config.elements['/config/post'] + process_post(file, config) + end + end + end - done = true - end - end + # Clean up the backup, we don't need it anymore + if config.elements['/config/test_before_post'] || + config.elements['/config/test'] + puts "Removing backup #{backup}" + remove_file(backup) if (!@dryrun); + end - if config.elements['/config/directory'] && !done # Directory - - # A little safety check - create = config.elements['/config/directory/create'] - abort "No create element found in directory section" if !create - - permstring = config.elements['/config/directory/perms'].text - perms = permstring.oct - owner = config.elements['/config/directory/owner'].text - group = config.elements['/config/directory/group'].text - uid = lookup_uid(owner) - gid = lookup_gid(group) + # Update the history log again + save_history(file) - set_directory = !File.directory?(file) || File.symlink?(file) - set_permissions = nil - set_ownership = nil - # If the file is currently something other than a directory then - # always set the flags to set the permissions and ownership. - # Checking the permissions/ownership of whatever is there currently - # is useless. - if set_directory - set_permissions = true - set_ownership = true - else - set_permissions = compare_permissions(file, perms) - set_ownership = compare_ownership(file, uid, gid) - ... [truncated message content] |
From: SourceForge.net <no...@so...> - 2008-11-25 02:18:34
|
Bugs item #2317757, was opened at 2008-11-20 07:14 Message generated for change (Settings changed) made by jheiss You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=1093658&aid=2317757&group_id=234501 Please note that this message will contain a full copy of the comment thread, including the initial issue submission, for this request, not just the latest update. Category: Default Group: None >Status: Closed >Resolution: Fixed Priority: 5 Private: No Submitted By: Nobody/Anonymous (nobody) Assigned to: Jason Heiss (jheiss) Summary: etch group failback error Initial Comment: The failback of the group ownerschip is wrong. It crashes: {{{ ./etch --generate-all --interactive --server http://localhost:3000 Destination /tmp/otherfile for link /tmp/etchdemo/link does not exist, consider the allow_nonexistent_dest flag if appropriate. ./etch.rb:1618:in `lookup_gid': uninitialized constant Errno::ArgumentError (NameError) from ./etch.rb:307:in `process' from ./etch.rb:156:in `process_until_done' from /usr/lib/ruby/1.8/rexml/element.rb:892:in `each' from /usr/lib/ruby/1.8/rexml/xpath.rb:53:in `each' from /usr/lib/ruby/1.8/rexml/element.rb:892:in `each' from ./etch.rb:154:in `process_until_done' from ./etch.rb:114:in `times' from ./etch.rb:114:in `process_until_done' from ./etch:90 }}} Here is the fix in etch.rb: {{{ begin gr = Etc.getgrnam(group) gid = gr.gid rescue ArgumentError puts "config.xml requests group #{group}, but that group can't be found. Using GID 0." gid = 0 end }}} ---------------------------------------------------------------------- >Comment By: Jason Heiss (jheiss) Date: 2008-11-24 18:18 Message: Etch 3.2 has been released which contains the fix for this bug. ---------------------------------------------------------------------- Comment By: Jason Heiss (jheiss) Date: 2008-11-24 14:59 Message: Sorry for the slow reply, I didn't realize I needed to configure Tracker to email me when there were new bugs. Strangely enough I found this bug myself right about the same time you did. My fix to lookup_gid is exactly the same as yours, and I made the same fix in lookup_uid. I'll go ahead and roll a new release. ---------------------------------------------------------------------- You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=1093658&aid=2317757&group_id=234501 |
From: SourceForge.net <no...@so...> - 2008-11-24 22:59:20
|
Bugs item #2317757, was opened at 2008-11-20 07:14 Message generated for change (Comment added) made by jheiss You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=1093658&aid=2317757&group_id=234501 Please note that this message will contain a full copy of the comment thread, including the initial issue submission, for this request, not just the latest update. Category: Interface (example) Group: None Status: Open >Resolution: Accepted Priority: 5 Private: No Submitted By: Nobody/Anonymous (nobody) Assigned to: Jason Heiss (jheiss) Summary: etch group failback error Initial Comment: The failback of the group ownerschip is wrong. It crashes: {{{ ./etch --generate-all --interactive --server http://localhost:3000 Destination /tmp/otherfile for link /tmp/etchdemo/link does not exist, consider the allow_nonexistent_dest flag if appropriate. ./etch.rb:1618:in `lookup_gid': uninitialized constant Errno::ArgumentError (NameError) from ./etch.rb:307:in `process' from ./etch.rb:156:in `process_until_done' from /usr/lib/ruby/1.8/rexml/element.rb:892:in `each' from /usr/lib/ruby/1.8/rexml/xpath.rb:53:in `each' from /usr/lib/ruby/1.8/rexml/element.rb:892:in `each' from ./etch.rb:154:in `process_until_done' from ./etch.rb:114:in `times' from ./etch.rb:114:in `process_until_done' from ./etch:90 }}} Here is the fix in etch.rb: {{{ begin gr = Etc.getgrnam(group) gid = gr.gid rescue ArgumentError puts "config.xml requests group #{group}, but that group can't be found. Using GID 0." gid = 0 end }}} ---------------------------------------------------------------------- >Comment By: Jason Heiss (jheiss) Date: 2008-11-24 14:59 Message: Sorry for the slow reply, I didn't realize I needed to configure Tracker to email me when there were new bugs. Strangely enough I found this bug myself right about the same time you did. My fix to lookup_gid is exactly the same as yours, and I made the same fix in lookup_uid. I'll go ahead and roll a new release. ---------------------------------------------------------------------- You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=1093658&aid=2317757&group_id=234501 |