lib/rpm_database.rb in machinery-tool-1.16.4 vs lib/rpm_database.rb in machinery-tool-1.17.0
- old
+ new
@@ -13,195 +13,19 @@
# along with this program; if not, contact SUSE LLC.
#
# To contact SUSE about this file by physical or electronic mail,
# you may find current contact information at www.suse.com
-class RpmDatabase
- class ChangedFile < Machinery::Object
- attr_accessor :type
-
- def initialize(type, attrs)
- super(attrs)
- @type = type
- end
-
- def config_file?
- @type == "c"
- end
+class RpmDatabase < ManagedFilesDatabase
+ def managed_files_list(&block)
+ @system.run_script_with_progress("changed_files.sh", &block)
end
- def initialize(system)
- @system = system
+ def package_for_file_path(file)
+ package = @system.run_command("rpm", "-qf", file, stdout: :capture).split.first
+ package_name, package_version = package.scan(/(.*)-([^-]*)-[^-]/).first
+ [package_name, package_version]
end
-
- def changed_files(&block)
- return @changed_files if @changed_files
- check_requirements
-
- out = @system.run_script_with_progress("changed_files.sh", &block)
- result = out.each_line.map do |line|
- line.chomp!
- next unless line.match(/^[^ ]+[ ]+. \/.*$/)
-
- file, changes, type = parse_rpm_changes_line(line)
-
- package = @system.run_command("rpm", "-qf", file, stdout: :capture).split.first
- package_name, package_version = package.scan(/(.*)-([^-]*)-[^-]/).first
-
- ChangedFile.new(
- type,
- name: file,
- package_name: package_name,
- package_version: package_version,
- status: "changed",
- changes: changes
- )
- end.compact.uniq
-
- paths = result.reject { |f| f.changes == Machinery::Array.new(["deleted"]) }.map(&:name)
- path_data = get_path_data(paths)
- result.each do |pkg|
- next unless path_data[pkg.name]
-
- path_data[pkg.name].each do |key, value|
- pkg[key] = value
- end
- end
-
- @changed_files = result
- end
-
- def expected_tag?(character, position)
- if @rpm_changes[position] == character
- true
- else
- @unknown_tag ||= ![".", "?"].include?(@rpm_changes[position])
- false
- end
- end
-
- def parse_rpm_changes_line(line)
- # rpm provides lines per config file where first 9 characters indicate which
- # properties of the file are modified
- @rpm_changes, *fields = line.split(" ")
- # nine rpm changes are known
- @unknown_tag = @rpm_changes.size > 9
-
- # For config or documentation files there's an additional field which
- # contains "c" or "d"
- type = fields[0].start_with?("/") ? "" : fields.shift
- path = fields.join(" ")
-
- changes = []
- if @rpm_changes == "missing"
- changes << "deleted"
- elsif @rpm_changes == "........." && path.end_with?(" (replaced)")
- changes << "replaced"
- path.slice!(/ \(replaced\)$/)
- else
- changes << "size" if expected_tag?("S", 0)
- changes << "mode" if expected_tag?("M", 1)
- changes << "md5" if expected_tag?("5", 2)
- changes << "device_number" if expected_tag?("D", 3)
- changes << "link_path" if expected_tag?("L", 4)
- changes << "user" if expected_tag?("U", 5)
- changes << "group" if expected_tag?("G", 6)
- changes << "time" if expected_tag?("T", 7)
- changes << "capabilities" if @rpm_changes.size > 8 && expected_tag?("P", 8)
- end
-
- if @unknown_tag
- changes << "other_rpm_changes"
- end
-
- if @rpm_changes.include?("?")
- message = "Could not perform all tests on rpm changes for file '#{path}'."
- Machinery.logger.warn(message)
- Machinery::Ui.warn("Warning: #{message}")
- end
-
- [path, changes, type]
- end
-
- def parse_stat_line(line)
- mode, user, group, uid, gid, type, *path_line = line.split(":")
- path = path_line.join(":").chomp
-
- user = uid if user == "UNKNOWN"
- group = gid if group == "UNKNOWN"
-
- type = case type
- when "directory"
- "dir"
- when "symbolic link"
- "link"
- when /file$/
- "file"
- else
- raise(
- "The inspection failed because of the unknown type `#{type}` of file `#{path}`."
- )
- end
-
- [path,
- {
- mode: mode,
- user: user,
- group: group,
- type: type
- }
- ]
- end
-
- def get_link_target(link)
- @system.run_command(
- "find", link, "-prune", "-printf", "%l",
- stdout: :capture,
- privileged: true
- ).strip
- end
-
- # get path data for list of files
- # cur_files is guaranteed to not exceed max command line length
- def get_file_properties(cur_files)
- ret = {}
- out = @system.run_command(
- "stat", "--printf", "%a:%U:%G:%u:%g:%F:%n\\n",
- *cur_files,
- stdout: :capture,
- privileged: true
- )
- out.each_line do |l|
- path, values = parse_stat_line(l)
- ret[path] = values
- ret[path][:target] = get_link_target(path) if values[:type] == "link"
- end
- ret
- end
-
- def get_path_data(paths)
- ret = {}
- path_index = 0
- # arbitrary number for maximum command line length that should always work
- max_len = 50000
- cur_files = []
- cur_len = 0
- while path_index < paths.size
- if cur_files.empty? || paths[path_index].size + cur_len + 1 < max_len
- cur_files << paths[path_index]
- cur_len += paths[path_index].size + 1
- path_index += 1
- else
- ret.merge!(get_file_properties(cur_files))
- cur_files.clear
- cur_len = 0
- end
- end
- ret.merge!(get_file_properties(cur_files)) unless cur_files.empty?
- ret
- end
-
- private
def check_requirements
@system.check_requirement("rpm", "--version")
@system.check_requirement("stat", "--version")
@system.check_requirement("find", "--version")