Hello community, here is the log from the commit of package yast2-installation for openSUSE:Leap:15.2 checked in at 2020-02-27 06:41:19 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Leap:15.2/yast2-installation (Old) and /work/SRC/openSUSE:Leap:15.2/.yast2-installation.new.26092 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "yast2-installation" Thu Feb 27 06:41:19 2020 rev:161 rq:779094 version:4.2.35 Changes: -------- --- /work/SRC/openSUSE:Leap:15.2/yast2-installation/yast2-installation.changes 2020-02-21 23:50:00.528644829 +0100 +++ /work/SRC/openSUSE:Leap:15.2/.yast2-installation.new.26092/yast2-installation.changes 2020-02-27 06:41:21.149590755 +0100 @@ -1,0 +2,26 @@ +Fri Feb 21 09:45:10 UTC 2020 - Ladislav Slezák <lsle...@suse.cz> + +- Added "yupdate" script to simplify patching the installer + (bsc#1163691) +- 4.2.35 + +------------------------------------------------------------------- +Thu Feb 20 15:12:39 UTC 2020 - Imobach Gonzalez Sosa <igonzalezs...@suse.com> + +- Rely on the new Y2Network::NtpServer class (jsc#SLE-7188). +- 4.2.34 + +------------------------------------------------------------------- +Thu Feb 20 11:24:41 UTC 2020 - Imobach Gonzalez Sosa <igonzalezs...@suse.com> + +- Allow to modify the control file at installation time using a + skelcd-* package (bsc#1164468). +- 4.2.33 + +------------------------------------------------------------------- +Wed Feb 19 09:40:45 UTC 2020 - Steffen Winterfeldt <snw...@suse.com> + +- don't start getty on hvc0 & ttyAMA0 before Yast2-Firstboot (bsc#1157233) +- 4.2.32 + +------------------------------------------------------------------- Old: ---- yast2-installation-4.2.31.tar.bz2 New: ---- yast2-installation-4.2.35.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ yast2-installation.spec ++++++ --- /var/tmp/diff_new_pack.ao5uLq/_old 2020-02-27 06:41:21.601591696 +0100 +++ /var/tmp/diff_new_pack.ao5uLq/_new 2020-02-27 06:41:21.605591705 +0100 @@ -17,7 +17,7 @@ Name: yast2-installation -Version: 4.2.31 +Version: 4.2.35 Release: 0 Summary: YaST2 - Installation Parts License: GPL-2.0-only @@ -42,8 +42,8 @@ BuildRequires: yast2-packager >= 4.2.27 # using /usr/bin/udevadm BuildRequires: yast2-storage-ng >= 4.2.71 -## y2remote based version -BuildRequires: yast2-network >= 4.0.13 +# Y2Network::NtpServer +BuildRequires: yast2-network >= 4.2.55 # new root password cwm widget BuildRequires: yast2-users >= 3.2.8 # storage-ng based version @@ -78,7 +78,8 @@ Requires: yast2-services-manager >= 3.2.1 # Yast::OSRelease.ReleaseVersionHumanReadable Requires: yast2 >= 4.2.56 -Requires: yast2-network >= 4.0.13 +# Y2Network::NtpServer +Requires: yast2-network >= 4.2.55 # for AbortException and handle direct abort Requires: yast2-ruby-bindings >= 4.0.6 # for the first/second stage of installation @@ -191,6 +192,8 @@ # systemd service files %{_unitdir} +# yupdate script +%{_bindir}/ %{yast_clientdir} %{yast_moduledir} %{yast_desktopdir} ++++++ YaST2-Firstboot.service ++++++ --- /var/tmp/diff_new_pack.ao5uLq/_old 2020-02-27 06:41:21.629591755 +0100 +++ /var/tmp/diff_new_pack.ao5uLq/_new 2020-02-27 06:41:21.629591755 +0100 @@ -3,6 +3,7 @@ After=apparmor.service local-fs.target plymouth-start.service YaST2-Second-Stage.service Conflicts=plymouth-start.service Before=getty@tty1.service serial-getty@ttyS0.service serial-getty@ttyS1.service serial-getty@ttyS2.service +Before=serial-getty@hvc0.service serial-getty@ttyAMA0.service Before=display-manager.service ConditionPathExists=/var/lib/YaST2/reconfig_system OnFailure=shutdown.target ++++++ YaST2-Second-Stage.service ++++++ --- /var/tmp/diff_new_pack.ao5uLq/_old 2020-02-27 06:41:21.641591779 +0100 +++ /var/tmp/diff_new_pack.ao5uLq/_new 2020-02-27 06:41:21.641591779 +0100 @@ -3,6 +3,7 @@ After=apparmor.service local-fs.target plymouth-start.service Conflicts=plymouth-start.service Before=getty@tty1.service serial-getty@ttyS0.service serial-getty@ttyS1.service serial-getty@ttyS2.service +Before=serial-getty@hvc0.service serial-getty@ttyAMA0.service Before=display-manager.service ConditionPathExists=/var/lib/YaST2/runme_at_boot ++++++ yast2-installation-4.2.31.tar.bz2 -> yast2-installation-4.2.35.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-installation-4.2.31/Rakefile new/yast2-installation-4.2.35/Rakefile --- old/yast2-installation-4.2.31/Rakefile 2020-02-18 10:19:25.000000000 +0100 +++ new/yast2-installation-4.2.35/Rakefile 2020-02-21 13:28:20.000000000 +0100 @@ -9,6 +9,7 @@ # TODO: move to src/client and verify if needed conf.install_locations["control/*.rb"] = Packaging::Configuration::YAST_DIR + "/clients" conf.install_locations["startup"] = Packaging::Configuration::YAST_LIB_DIR + conf.install_locations["bin/*"] = File.join(Packaging::Configuration::DESTDIR, "/usr/bin/") end # safety check - make sure the RNG file is up to date diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-installation-4.2.31/bin/yupdate new/yast2-installation-4.2.35/bin/yupdate --- old/yast2-installation-4.2.31/bin/yupdate 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-installation-4.2.35/bin/yupdate 2020-02-21 13:28:20.000000000 +0100 @@ -0,0 +1,771 @@ +#!/usr/bin/env ruby + +# This script updates the YaST files in the inst-sys with the files from +# a GitHub repository or a running tarball web server. +# +# See the help text below for the details or see the documentation in +# the doc/yupdate.md file. +# +# Note: The reason why all classes are in a single file is that +# it allows to easy update the script to the latest version +# or add it to an older (not supported) installer with: +# +# curl https://raw.githubusercontent.com/yast/yast-installation/master/bin/yupdate > /usr/bin/yupdate +# chmod +x /usr/bin/yupdate +# yupdate ... +# + +require "fileutils" +require "find" +require "json" +require "net/http" +require "open-uri" +require "pathname" +require "shellwords" +require "singleton" +require "socket" +require "tmpdir" +require "uri" + +# for logging to y2log +require "yast" + +module YUpdate + # version of the script + class Version + MAJOR = 0 + MINOR = 1 + PATCH = 0 + + STRING = "#{MAJOR}.#{MINOR}.#{PATCH}".freeze + end + + # handle the "help" command line option + class HelpCommand + def run + name = File.basename(__FILE__) + puts <<-HELP +This is a helper script for updating the YaST installer in the installation system. + +Usage: #{name} <command> <options> + +Commands: + + patch <github_repo> <branch> Patch the installer with the sources from GitHub, + <github_repo> is a repository name (including the organization + or the user name, if missing "yast" is used by default), + <branch> is the Git branch to use + + patch <tarball_url> Patch the installer with the sources provided by + a generic HTTP server + + patch <host[:port]> Patch the installer with the sources provided by + a "rake server" task (for details see + https://github.com/yast/yast-rake/#server), + the default port is 8000 + + servers <host[:port]> List the rake servers running on the remote machine, + ask the specified server to report all `rake server` + instances + + overlay create [<dir>] Create a new writable overlay for directory <dir>, + if no directory is specified it creates overlays + for the default YaST directories + + overlay list Print the created writable overlays + + overlay reset Remove all overlays, restore the system to + the original state + + overlay files Print the changed files (removed files are not listed) + + overlay diff Print the diff of the changed overlay files + + version Print the script version + + help Print this help + +WARNING: This script is intended only for testing and development purposes, + using this tool makes the installation not supported! + + See more details in + https://github.com/yast/yast-installation/blob/master/doc/yupdate.md +HELP + end + end + + # a helper module for printing and logging + module Logger + include Yast::Logger + + # print the message on STDOUT and also write it to the y2log + # @param message [String] the message + def msg(message) + puts message + log.info(message) + end + end + + # a simple /etc/install.inf parser/writer, + # we need to disable the YaST self-update feature to avoid conflicts + class InstallInf + attr_reader :path + + # read the file + def initialize(path = "/etc/install.inf") + @path = path + @values = File.read(path).lines.map(&:chomp) + end + + # get value for the key + def [](key) + line = find_line(key) + return nil unless line + + line.match(/^#{Regexp.escape(key)}:\s*(.*)/)[1] + end + + # set value for the key + def []=(key, val) + line = find_line(key) + + if line + # update the existing key + line.replace("#{key}: #{val}") + else + # add a new key + values << "#{key}: #{val}" + end + end + + # write the file back + def write + File.write(path, values.join("\n")) + end + + private + + attr_reader :values + + def find_line(key) + values.find { |l| l.start_with?(key + ":") } + end + end + + # Class for managing the OverlayFS mounts + # + # Each OverlayFS mount these directories: + # - upper and lower directories - the files in the upper directory + # shadow the files in the lower directory, the result can mounted + # at another 3rd place + # - working directory - for storing additional metadata + # (e.g. removed files) + # + # See more details in + # https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt + # + # The yupdate script uses /var/lib/YaST2/overlayfs for managing the OverlayFS, + # specifically: + # + # - /var/lib/YaST2/overlayfs/original - contains the original state + # - /var/lib/YaST2/overlayfs/upper - contains the new/changed files + # - /var/lib/YaST2/overlayfs/workdir - temporary metadata + # + # To avoid conflicts the original path names are converted to use the + # underscore (_) instead of slash (/) in the name, moreover the underscores + # are double-escaped to support underscores in the original names. E.g. + # /usr/lib/YaST2 (for which the real path is /mounts/mp_0001/usr/lib/YaST2 + # is mounted to /var/lib/YaST2/overlayfs/original/_mounts_mp__0001_usr_lib_YaST2. + class OverlayFS + include YUpdate::Logger + + OVERLAY_PREFIX = "/var/lib/YaST2/overlayfs".freeze + + YAST_OVERLAYS = [ + "/usr/lib/YaST2", + "/usr/lib64/YaST2", + "/usr/share/autoinstall", + "/usr/share/applications/YaST2" + ].freeze + + attr_reader :dir, :orig_dir + + # manage the OverlayFS for this directory + # @param directory [String] the directory + def initialize(directory) + @orig_dir = directory + # expand symlinks + @dir = File.realpath(directory) + raise "Path is not a directory: #{dir}" unless File.directory?(dir) + end + + # create an OverlayFS overlay for this directory if it is not writable + def create + return if File.writable?(dir) + msg "Adding overlay for #{orig_dir}..." + + FileUtils.mkdir_p(upperdir) + FileUtils.mkdir_p(workdir) + FileUtils.mkdir_p(origdir) + + # make the original content available in a separate directory + system("mount", "--bind", dir, origdir) + # mark the mount as a private otherwise the overlay would propagate + # through the bind mount and we would see the changed content here + system("mount", "--make-private", origdir) + + system("mount", "-t", "overlay", "overlay", "-o", "lowerdir=#{dir},"\ + "upperdir=#{upperdir},workdir=#{workdir}", dir) + end + + # delete the OverlayFS for this directory, all changes will be reverted back + def delete + system("umount", dir) + system("umount", origdir) + FileUtils.rm_rf([upperdir, workdir, origdir]) + end + + # print the modified files in this directory + def print_files + iterate_files { |f, _modif, _orig| puts f } + end + + # print the diff for the changed files in this directory + def print_diff + iterate_files do |f, _modif, orig| + next unless File.exist?(f) && File.exist?(orig) + system("diff", "-u", orig, f) + end + end + + # find all OverlayFS mounts in the system + def self.find_all + mounts = `mount` + mounts.lines.each_with_object([]) do |line, arr| + arr << new(Regexp.last_match[1]) if line =~ /^overlay on (.*) type overlay / + end + end + + # return the default set of YaST overlays + def self.default_overlays + yast_overlays.map { |o| new(o) } + end + + def upperdir + OverlayFS.escape_path("upper", dir) + end + + def workdir + OverlayFS.escape_path("workdir", dir) + end + + def origdir + OverlayFS.escape_path("original", dir) + end + + def self.escape_path(subdir, path) + # escape (double) underscores for correct reverse conversion + File.join(OVERLAY_PREFIX, subdir, path.gsub("_", "__").tr("/", "_")) + end + + def self.unescape_path(path) + Pathname.new(path).basename.to_s.gsub(/([^_])_([^_])/, "\\1/\\2") + .sub(/\A_/, "/").gsub("__", "_").gsub("//", "/") + end + + private + + # find the files in this directory + # the block is called with three parameters: + # - the path to the new file in the overlay directory + # - the original path in / + # - the path to the original file in the overlay directory + def iterate_files(&block) + return unless block_given? + + Find.find(upperdir) do |f| + next unless File.file?(f) + upperdir_path = Pathname.new(upperdir) + relative_path = Pathname.new(f).relative_path_from(upperdir_path) + original_path = File.join(origdir, relative_path) + # unescape the path + pth = unescape_path(upperdir_path) + block.call(File.join(pth, relative_path), f, original_path) + end + end + + def self.yast_overlays + # /usr/share/YaST2/ needs to be handled specially, it is writable + # but contains symlinks to read-only subdirectories, so let's make + # the subdirectories writable + YAST_OVERLAYS + Dir["/usr/share/YaST2/*"].each_with_object([]) do |f, arr| + arr << f if File.directory?(f) && !File.writable?(f) + end + end + + private_class_method :yast_overlays + end + + # a generic HTTP downloader + class Downloader + include YUpdate::Logger + attr_reader :url + + # Create the downloader for the specified URL (only HTTP/HTTPS is supported) + # @param url [String] the URL for downloading + def initialize(url) + @url = url + end + + # download the file, returns the response body or if a block is + # given it passes the response to it, handles HTTP redirection automatically + def download(&block) + msg "Downloading #{url}" + + if block_given? + URI.open(url) { |f| block.call(f) } + else + URI.open(url, &:read) + end + end + end + + # specialized tarball downloader, it can extract the downloaded + # tarball on the fly (without saving the actual tarball) to the target directory + class TarballDownloader < Downloader + def initialize(url) + super + end + + # start the downloading, extract the tarball to the specified directory + def extract_to(dir) + download do |input| + if input.content_type !~ /application\/(x-|)gzip/ + raise "Unknown MIME type: #{input.content_type}" + end + + # pipe the response body directly to the tar process + IO.popen(["tar", "-C", dir, "--warning=no-timestamp", "-xz"], "wb") do |io| + while (buffer = input.read(4096)) + io.write(buffer) + end + end + end + end + end + + # specialized tarball downloader which can download the sources + # from GitHub (the "git" tool is missing in the inst-sys), + # instead of "git clone" we download the archive tarball + class GithubDownloader < TarballDownloader + attr_reader :repo, :branch + + def initialize(repo, branch) + super("https://github.com/#{repo}/archive/#{branch}.tar.gz") + @repo = repo + @branch = branch + end + end + + # installing Ruby gems using the "gem" tool + class GemInstaller + # we need this gem for running the "rake install" command + NEEDED_GEM = "yast-rake".freeze + + # install the YaST required gems + def install_required_gems + install_gems(required_gems) + end + + private + + # is the gem installed? + def gem_installed?(gem_name) + gem(gem_name) + true + rescue Gem::LoadError + false + end + + # find the needed gems for running "rake install" + def required_gems + gems = [] + gems << NEEDED_GEM if !gem_installed?(NEEDED_GEM) + # handle the rake gem specifically, it is present in the system, but + # the /usr/bin/rake file is missing + gems << "rake" if !File.exist?("/usr/bin/rake") + gems + end + + # install the specified gems + def install_gems(gem_names) + return if gem_names.empty? + add_gem_overlay + system("gem", "install", "--no-document", "--no-format-exec", *gem_names) + end + + # make sure that the gem directory is writable + def add_gem_overlay + overlay = OverlayFS.new(Gem.dir) + overlay.create + end + end + + # install the YaST sources using the "rake install" call + class Installer + include YUpdate::Logger + + attr_reader :src_dir + + # @param src_dir [String] the source directory with unpacked sources + def initialize(src_dir) + @src_dir = src_dir + end + + # install the sources to the inst-sys + def install + Dir.mktmpdir do |tmp| + # first install the files into a temporary location + # using "rake install DESTDIR=..." + install_sources(tmp) + # then find the changed files and update them in the inst-sys + copy_to_system(tmp) + end + end + + private + + # globs for ignored some files + SKIP_FILES = [ + # vim temporary files + "*/.*swp", + # backup files + "*/*.bak", + # skip documentation + "/usr/share/doc/*", + # skip manual pages + "/usr/share/man/*", + # skip sysconfig templates + "/usr/share/fillup-templates/*" + ].freeze + + # install the sources to the specified (temporary) directory + def install_sources(target) + msg "Preparing files..." + + # check for Makefile.cvs, we cannot install packages using autotools + makefile_cvs = Dir["#{src_dir}/**/Makefile.cvs"].first + if makefile_cvs + raise "Found Makefile.cvs, autotools based packages cannot be installed!" + end + + rakefile = Dir["#{src_dir}/**/Rakefile"].first + raise "Rakefile not found, cannot install the package" unless rakefile + + src_dir = File.dirname(rakefile) + Dir.chdir(src_dir) do + `rake install DESTDIR=#{target.shellescape} 2> /dev/null` + end + end + + # should be the file skipped? + def skip_file?(file) + SKIP_FILES.any? { |glob| File.fnmatch?(glob, file) } + end + + # copy the changed files to the ins-sys + def copy_to_system(src) + msg "Copying to system..." + src_path = Pathname.new(src) + cnt = 0 + Find.find(src) do |path| + # TODO: what about symlinks or empty directories? + next unless File.file?(path) + + relative_path = Pathname.new(path).relative_path_from(src_path).to_s + system_file = File.absolute_path(relative_path, "/") + system_dir = File.dirname(system_file) + + next if skip_file?(system_file) + + if File.exist?(system_file) + next if FileUtils.identical?(system_file, path) + add_overlay(system_dir) + # replace a symlink (likely pointing to a read-only location) + FileUtils.rm_f(system_file) if File.symlink?(system_file) + FileUtils.cp(path, system_file) + msg "Updated: #{system_file}" + else + # ensure the directory is writable + if File.exist?(system_dir) + add_overlay(system_dir) + else + # FIXME: maybe an overlay is needed for the upper directory... + FileUtils.mkdir_p(system_dir) + end + + FileUtils.cp(path, system_file) + msg "Added: #{system_file}" + end + cnt += 1 + end + + msg "Number of modified files: #{cnt}" + end + + # ensure that the target directory is writable + def add_overlay(dir) + o = OverlayFS.new(dir) + o.create + end + end + + # handler for the "overlay" command option + class OverlayCommand + def initialize(argv) + @argv = argv + end + + def run + command = @argv.shift + + case command + when "list" + puts OverlayFS.find_all.map(&:dir) + when "create" + dir = @argv.shift + + if dir + ovfs = OverlayFS.new(dir) + ovfs.create + else + OverlayFS.default_overlays.map(&:create) + end + when "reset" + OverlayFS.find_all.map(&:delete) + when "files" + OverlayFS.find_all.map(&:print_files) + when "diff" + OverlayFS.find_all.map(&:print_diff) + else + InvalidCommand.new(command) + end + end + end + + # inst-sys test + class InstSys + # check if the script is running in the inst-sys, + # the script might not work as expected in an installed system + # and using OverlayFS is potentially dangerous + def self.check! + # the inst-sys contains the /.packages.initrd file with a list of packages + return if File.exist?("/.packages.initrd") + + # exit immediately if running in an installed system + $stderr.puts "ERROR: This script can only work in the installation system (inst-sys)!" + exit 1 + end + end + + # parse the command line options + class Options + def self.parse(argv) + command = argv.shift + + case command + when "version" + VersionCommand.new + when "overlay" + InstSys.check! + OverlayCommand.new(argv) + when "patch" + InstSys.check! + PatchCommand.new(argv) + when "servers" + ServersCommand.new(argv) + when "help", "--help", nil + HelpCommand.new + else + InvalidCommand.new(command) + end + end + end + + # handle the "version" command line option + class VersionCommand + def run + puts "#{File.basename(__FILE__)} #{Version::STRING}" + end + end + + # handle the "servers" command line option + class ServersCommand + def initialize(argv) + @argv = argv + end + + def run + host = @argv.shift + raise "Missing server name argument" unless host + + servers = RemoteServer.find(host) + servers.each do |s| + puts "URL: #{s.url}, directory: #{s.dir}" + end + end + end + + # handle the "patch" command line option + class PatchCommand + include YUpdate::Logger + + def initialize(argv) + @argv = argv + end + + def run + arg1 = @argv.shift + arg2 = @argv.shift + + return 1 unless arg1 + + prepare_system + + if arg1 && arg2 + # update from github + install_from_github(arg1, arg2) + elsif arg1.start_with?("http") && arg1.end_with?(".tar.gz") + # upgrade from URL + install_from_tar(arg1) + elsif !arg2 + # otherwise treat it as a hostname providing a tarball server + install_from_servers(arg1) + else + raise "Invalid arguments" + end + + # TODO: only when something has been updated? + disable_self_update + end + + private + + def install_from_github(repo, branch) + # add the default "yast" GitHub organization if missing + repo = "yast/#{repo}" unless repo.include?("/") + downloader = GithubDownloader.new(repo, branch) + install_tar(downloader) + end + + def install_from_tar(url) + downloader = TarballDownloader.new(url) + install_tar(downloader) + end + + def install_from_servers(hostname) + servers = RemoteServer.find(hostname) + + servers.each do |s| + msg "Installing from #{s.url}..." + url = "#{s.url}/archive/current.tar.gz" + install_from_tar(url) + end + end + + def install_sources(src_dir) + i = Installer.new(src_dir) + i.install + end + + # prepare the inst-sys for installation: + # - make the YaST directories writable + # - install the needed Ruby gems (yast-rake) + def prepare_system + OverlayFS.default_overlays.map(&:create) + g = GemInstaller.new + g.install_required_gems + end + + def install_tar(downloader) + Dir.mktmpdir do |download_dir| + downloader.extract_to(download_dir) + install_sources(download_dir) + end + end + + # /etc/install.inf key + SELF_UPDATE_KEY = "SelfUpdate".freeze + + # disable the self update in the install.inf file + def disable_self_update + inf = InstallInf.new + return if inf[SELF_UPDATE_KEY] == "0" + + msg "Disabling the YaST SelfUpdate feature in install.inf!" + inf[SELF_UPDATE_KEY] = "0" + inf.write + end + end + + # handle invalid command line options + class InvalidCommand + def initialize(cmd) + @cmd = cmd + end + + def run + raise "Invalid command: #{cmd}" + end + + private + + attr_reader :cmd + end + + # Query the remote server for the running servers + class RemoteServer + attr_reader :url, :dir + + def initialize(url, dir) + @url = url + @dir = dir + end + + def self.find(host) + host += ":8000" unless host.include?(":") + + url = "http://#{host}/servers/index.json" + u = URI(url) + u.path = "" + + downloader = Downloader.new(url) + JSON.parse(downloader.download).map do |server| + u.port = server["port"] + new(u.to_s, server["dir"]) + end + end + end + + # the main script application + class Application + include YUpdate::Logger + + def run(argv = ARGV) + cmd = Options.parse(argv) + cmd.run + rescue StandardError => e + # the global exception handler + msg("ERROR: #{e.message}") + exit 1 + end + end +end + +# do not execute the script when the file is loaded by some other script +# e.g. by a test, allow testing parts of the code without executing it as a whole +if __FILE__ == $PROGRAM_NAME + # main + app = YUpdate::Application.new + app.run +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-installation-4.2.31/doc/yupdate.md new/yast2-installation-4.2.35/doc/yupdate.md --- old/yast2-installation-4.2.31/doc/yupdate.md 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-installation-4.2.35/doc/yupdate.md 2020-02-21 13:28:20.000000000 +0100 @@ -0,0 +1,260 @@ +# The yupdate Script + +This is a documentation for the `yupdate` helper script, +which is included in the YaST installer in SLE15-SP2/openSUSE +Leap 15.2 (or newer) and in the openSUSE Tumbleweed since +build 2020xxxx. + +## The Introduction + +**Problem**: You are developing a feature for the installer and you need to +test your changes frequently. For extra fun, the change is spread across +multiple repositories. + +The YaST installation system is quite different to an +usual Linux installed system. The root filesystem +is stored in a RAM disk and most files are read-only. +That makes it quite difficult to modify the YaST installer +if you need to debug a problem or test a fix. + +There are some possibilities for updating the YaST installer +(see [Alternative](#Alternative)) +but they are usually not trivial and need special preparations. +For this reason we created a special `yupdate` script which makes +the process easier. + +However, in some cases this easier way cannot be used, see the +[limitations](#limitations) section below. + + +## Self-update + +After patching the installer the `yupdate` script disables +the YaST self-update feature because it could conflict with it +and overwrite the changes. + +If you need some changes from the self-update then use the `startshell=1` +boot option, start the installer and allow the self-update step to finish, +then abort the installation and use the `ypdate` script to apply the +changes on top of the self-update. + +## Warning + +:warning: **Patching the installer with the `yupdate` script makes +the installation unsupported!** :warning: + +The script is intended for developers to test new features or bug fixes. + +It can be used by customers for testing as well, but it should not be used +on production systems! + +## Installation + +The `yupdate` script should run in the inst-sys. Since SLE15-SP2/openSUSE +Leap 15.2, openSUSE Tumbleweed 2020xxxx, it ~~is~~ will be preinstalled. + +For older releases, run: + +```shell +curl https://raw.githubusercontent.com/yast/yast-installation/master/bin/yupdate > /usr/bin/yupdate +chmod +x /usr/bin/yupdate +``` + +You can also use this command to update the included script +to the latest version. + +## Basic Use Cases + +This script is intended to help in the following scenarios. + +### Make the inst-sys Writable + +As already mentioned, the files in the installation system are read only. To be +able to patch the installer the script must be able to make the files writable. +It does that automatically for the updated files, but maybe you would like to +use this feature also for some other non-YaST files. + +To make a directory writable in the inst-sys run command + +```shell +yupdate overlay create <dir> +``` + +This will create a writable overlay above the specified directory. If you do not +specify any directory it will create writable overlays for the default YaST +directories. + +Then you can easily edit the files using the included `vim` editor +or by other tools like `sed` or overwrite by external files. + +### Patch YaST from GitHub Sources + +To update or install an YaST package directly from the GitHub source code +repository use command + +```shell +yupdate patch <github_slug> <branch> +``` + +where `github_slug` is a `user`/`repository` name, if the `user` value is +missing the default "yast" is used. The `branch` in the source branch to +install, for example `master` or `SLE-15-SP2`. + + +#### Examples + +```shell +# install the latest version of yast2-installation from upstream +yupdate patch yast-installation master +# install from a fork +yupdate patch my_fork/yast-installation my_branch +``` + +#### Notes + +- Make sure that you use a branch compatible with the running inst-sys, + installing the latest version in an older release might not work + as expect, the installer might crash or behave unexpectedly. +- There is no dependency resolution, if the new installed package + requires newer dependant packages then they must be installed manually. + +### Patch YaST from Locally Modified Sources + +Installing from GitHub sources is easy, but sometimes you do not want to +push every single change to GitHub, you would like to just use the current +files from you local Git checkout. + +In that case run + +```shell +rake server +``` + +in your YaST module Git checkout. This will run a web server providing source +tarball similar to the GitHub archive used in the previous case. + +*Note: You need "yast-rake" Ruby gem version 0.2.37 or newer.* + +Then run + +```shell +yupdate patch <host_name> +``` + +where `<host_name>` is the machine host name or the IP address where you run +the `rake server` task. To make it easier the rake task prints these values at +the start. + +By default this will use port 8000, if the server uses another port just add +`:` followed by the port number. + +*Note: Make sure the server port is open in the firewall configuration, +see the [documentation](https://github.com/yast/yast-rake/#server) for +more details.* + +#### Patching Multiple Packages + +The `yupdate patch` command installs the sources from all running `rake server` +servers. If you need to update sources from several packages you can just +run `rake server` in all of them and install them with a single `yupdate` +call. + +### Patch YaST from a Generic Tarball Archive + +This is similar to the previous cases, but the source tarball is not generated +dynamically by a server, but it is a statically hosted file. + +Example: + +```shell +yupdate patch http://myserver.example.com/test/yast2.tar.gz +``` + +## Other Commands + +### Listing OverlayFS Mounts + +To see the list of mounted OverlayFS run + +```shell +yupdate overlay list +``` + +### Listing Updated Files + +To see the list of changed files + +```shell +yupdate overlay files +``` + +### Displaying Changes in the System + +To see the applied changes to the system run + +```shell +yupdate overlay diff +``` + +This will display a diff for all changed files, it does not report +deleted or new files. + +### Restoring the System + +To revert all changes run + +```shell +yupdate overlay reset +``` + +This will remove *all* OverlayFS mounts and restore the system to the original +state. + +## Limitations + +- The script only works with Ruby source files, it cannot compile and + install C/C++ or other sources (the compiler and development libraries + are missing in the inst-sys) +- Works only with the packages which use `Rakefile` for installation, + it does not work with autotools based packages (again, autoconf/automake + are also missing in the inst-sys) + +## Alternative + +1. For all repos, run `rake osc:build` +2. Collect the resulting RPMs +3. Run a server, eg. with `ruby -run -e httpd -- -p 8888 .` +4. Type a loooong boot line to pass them all as DUD=http://....rpm + (or write that into a file and use the [info]( + https://en.opensuse.org/SDB:Linuxrc#p_info) option + or build a single DUD file from the RPMs with the [`mkdud`]( + https://github.com/wfeldt/mkdud) script) + +## Implementation Details + +### OverlayFS + +To make the inst-sys directories writable we use the Linux OverlayFS +which can merge already existing file systems ("union filesystem"). + +See more details in the [Linux Kernel Documentation]( +https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt). + +### Installing the Files + +For installing the sources the script uses the `rake install DESTDIR=...` +command and install the files into a temporary directory. Then it compares +the new files with the original files and if there is a change the old +file is rewritten by the new file. + +This also skips some not needed files like documentation, manual pages, +editor backup files, etc... + +This saves some memory as we do not need to shadow the not modified files +with the same content. + +### Logging + +The messages printed on the console are also saved in the `y2log` file. +That means it should be easy to find out that someone patched the installer +when analyzing logs from a bug report. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-installation-4.2.31/package/YaST2-Firstboot.service new/yast2-installation-4.2.35/package/YaST2-Firstboot.service --- old/yast2-installation-4.2.31/package/YaST2-Firstboot.service 2020-02-18 10:19:25.000000000 +0100 +++ new/yast2-installation-4.2.35/package/YaST2-Firstboot.service 2020-02-21 13:28:20.000000000 +0100 @@ -3,6 +3,7 @@ After=apparmor.service local-fs.target plymouth-start.service YaST2-Second-Stage.service Conflicts=plymouth-start.service Before=getty@tty1.service serial-getty@ttyS0.service serial-getty@ttyS1.service serial-getty@ttyS2.service +Before=serial-getty@hvc0.service serial-getty@ttyAMA0.service Before=display-manager.service ConditionPathExists=/var/lib/YaST2/reconfig_system OnFailure=shutdown.target diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-installation-4.2.31/package/YaST2-Second-Stage.service new/yast2-installation-4.2.35/package/YaST2-Second-Stage.service --- old/yast2-installation-4.2.31/package/YaST2-Second-Stage.service 2020-02-18 10:19:25.000000000 +0100 +++ new/yast2-installation-4.2.35/package/YaST2-Second-Stage.service 2020-02-21 13:28:20.000000000 +0100 @@ -3,6 +3,7 @@ After=apparmor.service local-fs.target plymouth-start.service Conflicts=plymouth-start.service Before=getty@tty1.service serial-getty@ttyS0.service serial-getty@ttyS1.service serial-getty@ttyS2.service +Before=serial-getty@hvc0.service serial-getty@ttyAMA0.service Before=display-manager.service ConditionPathExists=/var/lib/YaST2/runme_at_boot diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-installation-4.2.31/package/yast2-installation.changes new/yast2-installation-4.2.35/package/yast2-installation.changes --- old/yast2-installation-4.2.31/package/yast2-installation.changes 2020-02-18 10:19:25.000000000 +0100 +++ new/yast2-installation-4.2.35/package/yast2-installation.changes 2020-02-21 13:28:20.000000000 +0100 @@ -1,4 +1,30 @@ ------------------------------------------------------------------- +Fri Feb 21 09:45:10 UTC 2020 - Ladislav Slezák <lsle...@suse.cz> + +- Added "yupdate" script to simplify patching the installer + (bsc#1163691) +- 4.2.35 + +------------------------------------------------------------------- +Thu Feb 20 15:12:39 UTC 2020 - Imobach Gonzalez Sosa <igonzalezs...@suse.com> + +- Rely on the new Y2Network::NtpServer class (jsc#SLE-7188). +- 4.2.34 + +------------------------------------------------------------------- +Thu Feb 20 11:24:41 UTC 2020 - Imobach Gonzalez Sosa <igonzalezs...@suse.com> + +- Allow to modify the control file at installation time using a + skelcd-* package (bsc#1164468). +- 4.2.33 + +------------------------------------------------------------------- +Wed Feb 19 09:40:45 UTC 2020 - Steffen Winterfeldt <snw...@suse.com> + +- don't start getty on hvc0 & ttyAMA0 before Yast2-Firstboot (bsc#1157233) +- 4.2.32 + +------------------------------------------------------------------- Mon Feb 17 17:44:48 UTC 2020 - Stefan Hundhammer <shundham...@suse.com> - Fixed user-visible messages (bsc#1084015) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-installation-4.2.31/package/yast2-installation.spec new/yast2-installation-4.2.35/package/yast2-installation.spec --- old/yast2-installation-4.2.31/package/yast2-installation.spec 2020-02-18 10:19:25.000000000 +0100 +++ new/yast2-installation-4.2.35/package/yast2-installation.spec 2020-02-21 13:28:20.000000000 +0100 @@ -16,7 +16,7 @@ # Name: yast2-installation -Version: 4.2.31 +Version: 4.2.35 Release: 0 Group: System/YaST License: GPL-2.0-only @@ -41,8 +41,8 @@ BuildRequires: yast2-packager >= 4.2.27 # using /usr/bin/udevadm BuildRequires: yast2-storage-ng >= 4.2.71 -## y2remote based version -BuildRequires: yast2-network >= 4.0.13 +# Y2Network::NtpServer +BuildRequires: yast2-network >= 4.2.55 # new root password cwm widget BuildRequires: yast2-users >= 3.2.8 # storage-ng based version @@ -77,7 +77,8 @@ Requires: yast2-services-manager >= 3.2.1 # Yast::OSRelease.ReleaseVersionHumanReadable Requires: yast2 >= 4.2.56 -Requires: yast2-network >= 4.0.13 +# Y2Network::NtpServer +Requires: yast2-network >= 4.2.55 # for AbortException and handle direct abort Requires: yast2-ruby-bindings >= 4.0.6 # for the first/second stage of installation @@ -192,6 +193,8 @@ # systemd service files %{_unitdir} +# yupdate script +%{_bindir}/ %{yast_clientdir} %{yast_moduledir} %{yast_desktopdir} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-installation-4.2.31/src/lib/installation/dialogs/ntp_setup.rb new/yast2-installation-4.2.35/src/lib/installation/dialogs/ntp_setup.rb --- old/yast2-installation-4.2.31/src/lib/installation/dialogs/ntp_setup.rb 2020-02-18 10:19:25.000000000 +0100 +++ new/yast2-installation-4.2.35/src/lib/installation/dialogs/ntp_setup.rb 2020-02-21 13:28:20.000000000 +0100 @@ -22,6 +22,7 @@ require "yast" require "cwm/dialog" require "installation/widgets/ntp_server" +require "y2network/ntp_server" module Installation module Dialogs @@ -68,7 +69,7 @@ # TODO: use Yast::NtpClient.ntp_conf if configured # to better handle going back servers = dhcp_ntp_servers - servers = [ntp_fallback] if servers.empty? && default_ntp_setup_enabled? + servers = [ntp_fallback.hostname] if servers.empty? && default_ntp_setup_enabled? servers end @@ -98,23 +99,11 @@ # The fallback servers for NTP configuration # - # It propose a random pool server in range 0..3 + # It propose a random server from the default pool # - # @return [String] the fallback servers + # @return [Y2Network::NtpServer] the fallback server def ntp_fallback - "#{rand(4)}.#{ntp_host}.pool.ntp.org" - end - - def ntp_host - # copied from timezone/dialogs.rb: - base_products = Yast::Product.FindBaseProducts - - if base_products.any? { |p| p["name"] =~ /openSUSE/i } - "opensuse" - else - # TODO: use a SUSE server when available in the future - "novell" - end + Y2Network::NtpServer.default_servers.sample end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-installation-4.2.31/src/lib/installation/updates_manager.rb new/yast2-installation-4.2.35/src/lib/installation/updates_manager.rb --- old/yast2-installation-4.2.31/src/lib/installation/updates_manager.rb 2020-02-18 10:19:25.000000000 +0100 +++ new/yast2-installation-4.2.35/src/lib/installation/updates_manager.rb 2020-02-21 13:28:20.000000000 +0100 @@ -16,6 +16,7 @@ require "pathname" require "installation/driver_update" require "installation/update_repository" +require "yast2/execute" module Installation # This class takes care of managing installer updates @@ -110,14 +111,27 @@ # @see Installation::UpdateRepository#apply # @see Installation::DriverUpdate#apply # @see #repositories + # @raise CouldNotUpdateControlFile def apply_all (repositories + driver_updates).each(&:apply) repositories.each(&:cleanup) + replace_control_file end # Determines whether the manager has repositories with updates def repositories? !repositories.empty? end + + private + + NEW_CONTROL_FILE_PATH = "/usr/lib/skelcd/CD1/control.xml".freeze + + # Replaces the control file with the updated one (if it exists) + def replace_control_file + return unless File.exist?(NEW_CONTROL_FILE_PATH) + log.info("Updating control.xml file in inst-sys") + Yast::Execute.locally!("/sbin/adddir", File.dirname(NEW_CONTROL_FILE_PATH), "/") + end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-installation-4.2.31/test/dialogs/ntp_setup_test.rb new/yast2-installation-4.2.35/test/dialogs/ntp_setup_test.rb --- old/yast2-installation-4.2.31/test/dialogs/ntp_setup_test.rb 2020-02-18 10:19:25.000000000 +0100 +++ new/yast2-installation-4.2.35/test/dialogs/ntp_setup_test.rb 2020-02-21 13:28:20.000000000 +0100 @@ -36,16 +36,22 @@ end context "no NTP server set in DHCP and default NTP is enabled in control.xml" do + let(:default_servers) do + [ + Y2Network::NtpServer.new("0.opensuse.pool.ntp.org"), + Y2Network::NtpServer.new("1.opensuse.pool.ntp.org") + ] + end + before do allow(Yast::ProductFeatures).to receive(:GetBooleanFeature) .with("globals", "default_ntp_setup").and_return(true) - allow(Yast::Product).to receive(:FindBaseProducts) - .and_return(["name" => "openSUSE-Tumbleweed-Kubic"]) + allow(Y2Network::NtpServer).to receive(:default_servers).and_return(default_servers) end - it "proposes to use a random openSUSE pool server" do + it "proposes to use a random server from the default pool" do expect(::Installation::Widgets::NtpServer).to receive(:new).and_wrap_original do |original, arg| - expect(arg.first).to match(/\A[0-3]\.opensuse\.pool\.ntp\.org\z/) + expect(default_servers.map(&:hostname)).to include(arg.first) original.call(arg) end subject.run diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-installation-4.2.31/test/helpers.rb new/yast2-installation-4.2.35/test/helpers.rb --- old/yast2-installation-4.2.31/test/helpers.rb 2020-02-18 10:19:25.000000000 +0100 +++ new/yast2-installation-4.2.35/test/helpers.rb 2020-02-21 13:28:20.000000000 +0100 @@ -20,4 +20,21 @@ def load_fixture(*path) File.read(fixtures_dir(*path)) end + + # Execute the passed block and capture both $stdout and $stderr streams. + # @return [Array] A [STDOUT, STDERR] pair + def capture_stdio + stdout_orig = $stdout + stderr_orig = $stderr + + begin + $stdout = StringIO.new + $stderr = StringIO.new + yield + [$stdout.string, $stderr.string] + ensure + $stdout = stdout_orig + $stderr = stderr_orig + end + end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-installation-4.2.31/test/test_helper.rb new/yast2-installation-4.2.35/test/test_helper.rb --- old/yast2-installation-4.2.31/test/test_helper.rb 2020-02-18 10:19:25.000000000 +0100 +++ new/yast2-installation-4.2.35/test/test_helper.rb 2020-02-21 13:28:20.000000000 +0100 @@ -45,8 +45,9 @@ add_filter "/test/" end + bindir = File.expand_path("../../bin", __FILE__) # For coverage we need to load all ruby files - SimpleCov.track_files("#{srcdir}/**/*.rb") + SimpleCov.track_files("{#{srcdir}/**/*.rb,#{bindir}/*}") # use coveralls for on-line code coverage reporting at Travis CI if ENV["TRAVIS"] @@ -63,3 +64,14 @@ config.include Yast::I18n # available in it/let/before/... config.include Helpers # custom helpers end + +# require the "bin/yupdate" script for testing it, unfortunately we cannot use +# a simple require/require_relative for it, let's share the workaround in a single place +def require_yupdate + # - "require"/"require_relative" do not work for files without the ".rb" extension + # - adding the "yupdate.rb" -> "yupdate" symlink works but then code coverage + # somehow does not find the executed code and reports zero coverage there + # - "load" works fine but we need to ensure calling it only once + # to avoid the "already initialized constant" Ruby warnings + load File.expand_path("../bin/yupdate", __dir__) unless defined?(YUpdate) +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-installation-4.2.31/test/updates_manager_test.rb new/yast2-installation-4.2.35/test/updates_manager_test.rb --- old/yast2-installation-4.2.31/test/updates_manager_test.rb 2020-02-18 10:19:25.000000000 +0100 +++ new/yast2-installation-4.2.35/test/updates_manager_test.rb 2020-02-21 13:28:20.000000000 +0100 @@ -102,8 +102,12 @@ end describe "#apply_all" do + let(:new_control_file?) { false } + before do allow(manager).to receive(:repositories).and_return([repo0, repo1]) + allow(File).to receive(:exist?).with("/usr/lib/skelcd/CD1/control.xml") + .and_return(new_control_file?) end it "applies all the updates" do @@ -124,6 +128,22 @@ manager.apply_all end end + + context "when a new control file is available" do + let(:new_control_file?) { true } + + it "updates the control file" do + expect(Yast::Execute).to receive(:locally!) + .with("/sbin/adddir", "/usr/lib/skelcd/CD1", "/") + manager.apply_all + end + end + + it "does not replace the control file" do + expect(Yast::Execute).to_not receive(:locally!) + .with("/sbin/adddir", /skelcd/, "/") + manager.apply_all + end end describe "#repositories?" do diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-installation-4.2.31/test/yupdate/gem_installer_test.rb new/yast2-installation-4.2.35/test/yupdate/gem_installer_test.rb --- old/yast2-installation-4.2.31/test/yupdate/gem_installer_test.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-installation-4.2.35/test/yupdate/gem_installer_test.rb 2020-02-21 13:28:20.000000000 +0100 @@ -0,0 +1,40 @@ +#! /usr/bin/env rspec + +require_relative "../test_helper" +require_yupdate + +describe YUpdate::GemInstaller do + describe "#install_required_gems" do + before do + allow(File).to receive(:exist?).with("/usr/bin/rake").and_return(true) + allow_any_instance_of(YUpdate::OverlayFS).to receive :create + allow(subject).to receive(:gem).and_raise(Gem::LoadError) + allow(subject).to receive(:system) + end + + it "installs the required gems" do + expect(subject).to receive(:system).with( + "gem", + "install", + "--no-document", + "--no-format-exec", + "yast-rake" + ) + subject.install_required_gems + end + + it "skips already installed gems" do + expect(subject).to receive(:gem).and_return(true) + expect(subject).to_not receive(:system) + subject.install_required_gems + end + + it "it makes the gem directory writable" do + ovfs = double + expect(YUpdate::OverlayFS).to receive(:new).with(Gem.dir).and_return(ovfs) + expect(ovfs).to receive(:create) + + subject.install_required_gems + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-installation-4.2.31/test/yupdate/inst_sys_test.rb new/yast2-installation-4.2.35/test/yupdate/inst_sys_test.rb --- old/yast2-installation-4.2.31/test/yupdate/inst_sys_test.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-installation-4.2.35/test/yupdate/inst_sys_test.rb 2020-02-21 13:28:20.000000000 +0100 @@ -0,0 +1,39 @@ +#! /usr/bin/env rspec + +require_relative "../test_helper" +require_yupdate + +describe YUpdate::InstSys do + let(:file) { "/.packages.initrd" } + + describe ".check!" do + context "when running in an inst-sys" do + before do + expect(File).to receive(:exist?).with(file).and_return(true) + end + + it "does not exit" do + expect(described_class).to_not receive(:exit) + described_class.check! + end + end + + context "when running in a normal system" do + before do + expect(File).to receive(:exist?).with(file).and_return(false) + allow(described_class).to receive(:exit).with(1) + end + + it "exits with status 1" do + expect(described_class).to receive(:exit).with(1) + # capture the std streams just to not break the rspec output + capture_stdio { described_class.check! } + end + + it "prints an error on STDERR" do + _stdout, stderr = capture_stdio { described_class.check! } + expect(stderr).to match(/ERROR: .*inst-sys/) + end + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-installation-4.2.31/test/yupdate/overlayfs_test.rb new/yast2-installation-4.2.35/test/yupdate/overlayfs_test.rb --- old/yast2-installation-4.2.31/test/yupdate/overlayfs_test.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-installation-4.2.35/test/yupdate/overlayfs_test.rb 2020-02-21 13:28:20.000000000 +0100 @@ -0,0 +1,35 @@ +#! /usr/bin/env rspec + +require_relative "../test_helper" +require_yupdate + +describe YUpdate::OverlayFS do + # testing data + let(:orig_path) { "/test/test__test" } + let(:escaped_path) { "/var/lib/YaST2/overlayfs/upper/_test_test____test" } + + before do + # mock the checks for existing directory + allow(File).to receive(:realpath) { |d| d } + allow(File).to receive(:directory?).and_return(true) + end + + describe "#upperdir" do + it "returns the path in the 'upper' subdirectory" do + o = YUpdate::OverlayFS.new(orig_path) + expect(o.upperdir).to match(/\/upper\//) + end + end + + describe ".escape_path" do + it "escapes the path and adds a prefix" do + expect(YUpdate::OverlayFS.escape_path("upper", orig_path)).to eq(escaped_path) + end + end + + describe ".unescape_path" do + it "unescapes the path and removes the prefix" do + expect(YUpdate::OverlayFS.unescape_path(escaped_path)).to eq(orig_path) + end + end +end