Class: Installation::UpdateRepository

Inherits:
Object
  • Object
show all
Includes:
Yast::I18n, Yast::Logger
Defined in:
src/lib/installation/update_repository.rb

Overview

Represents a update repository to be used during self-update (check doc/SELF_UPDATE.md for details).

Examples:

Fetching and applying an update

begin
  repo = UpdateRepository.new(URI("http://update.opensuse.org/42.1"))
  repo.fetch
  repo.apply
ensure
  repo.cleanup
end

Fetching and applying to non-standard places

begin
  repo = UpdateRepository.new(URI("http://update.opensuse.org/42.1"))
  repo.fetch(Pathname("/downloading"))
  repo.apply(Pathname("/updates"))
ensure
  repo.cleanup
end

Defined Under Namespace

Classes: CouldNotBeApplied, CouldNotExtractPackage, CouldNotFetchUpdate, CouldNotMountUpdate, CouldNotProbeRepo, CouldNotRefreshRepo, CouldNotSquashPackage, FetchError, NotValidRepo, PackageNotFound, UnknownOrigin, UpdatesNotFetched

Constant Summary collapse

ORIGINS =

Where the repository information comes from

  • :default: Default
  • :user: User defined
[:default, :user].freeze
INSTSYS_PARTS_PATH =

Path to instsys.parts registry

Pathname("/etc/instsys.parts")
PACKAGE_INDEX =

a file with list of applied packages

"/.packages.self_update".freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(uri, origin = :default) ⇒ UpdateRepository

Constructor

Parameters:

  • uri (URI)

    Repository URI

  • origin (Symbol) (defaults to: :default)

    Repository origin (@see ORIGINS)

Raises:



121
122
123
124
125
126
127
128
129
130
# File 'src/lib/installation/update_repository.rb', line 121

def initialize(uri, origin = :default)
  textdomain "installation"

  @uri = uri
  @updates_file = nil
  @packages = nil
  raise UnknownOrigin unless ORIGINS.include?(origin)

  @origin = origin
end

Instance Attribute Details

#originSymbol (readonly)

Returns Repository origin. @see ORIGINS.

Returns:

  • (Symbol)

    Repository origin. @see ORIGINS



68
69
70
# File 'src/lib/installation/update_repository.rb', line 68

def origin
  @origin
end

#repo_idFixnum

Returns the repository ID

As a potential side-effect, the repository will be added to libzypp (if it was not added yet) in order to get the ID.

Returns:

  • (Fixnum)

    yast2-pkg-bindings ID of the repository

See Also:

  • #add_repo


140
141
142
# File 'src/lib/installation/update_repository.rb', line 140

def repo_id
  add_repo
end

#updates_fileArray<Pathname> (readonly)

Returns squash filesystem path.

Returns:

  • (Array<Pathname>)

    squash filesystem path



66
67
68
# File 'src/lib/installation/update_repository.rb', line 66

def updates_file
  @updates_file
end

#uriURI (readonly)

Returns URI of the repository.

Returns:

  • (URI)

    URI of the repository



64
65
66
# File 'src/lib/installation/update_repository.rb', line 64

def uri
  @uri
end

Instance Method Details

#apply(mount_path = Pathname("/mounts")) ⇒ Object

Apply updates to inst-sys

It happens in two phases (for each update/package):

  • Mount the squashfs filesystem
  • Add files/directories to inst-sys using the /sbin/adddir script

Parameters:

  • mount_path (Pathname) (defaults to: Pathname("/mounts"))

    Directory to mount the update

Raises:

  • UpdatesNotFetched

See Also:

  • #mount_squashfs
  • #adddir


220
221
222
223
224
225
226
227
228
# File 'src/lib/installation/update_repository.rb', line 220

def apply(mount_path = Pathname("/mounts"))
  raise UpdatesNotFetched if updates_file.nil?

  mountpoint = next_name(mount_path, length: 4)
  mount_squashfs(updates_file, mountpoint)
  adddir(mountpoint)
  update_instsys_parts(updates_file, mountpoint)
  write_package_index
end

#cleanupObject

Clean-up

Release the repository



233
234
235
236
237
238
# File 'src/lib/installation/update_repository.rb', line 233

def cleanup
  Yast::Pkg.SourceReleaseAll
  Yast::Pkg.SourceDelete(repo_id)
  # make sure it's also removed from disk
  Yast::Pkg.SourceSaveAll
end

#empty?Boolean

Determine whether the repository is empty or not

Returns:

  • (Boolean)

    true if the repository is empty; false otherwise.



243
244
245
# File 'src/lib/installation/update_repository.rb', line 243

def empty?
  Y2Packager::Resolvable.none?(kind: :package, source: repo_id)
end

#fetch(path = Pathname("/download")) ⇒ Pathname

Fetch updates and save them in a squasfs filesystem

Updates will be stored in the given directory.

If a known error occurs, it will be converted to a CouldNotFetchUpdate exception.

A progress is displayed when the packages are downloaded. The progress can be disabled by calling Yast::Progress.set(false).

Parameters:

  • path (Pathname) (defaults to: Pathname("/download"))

    Directory to store the updates

Returns:

  • (Pathname)

    Paths to the updates

Raises:

  • CouldNotFetchUpdate

See Also:

  • #fetch_and_extract_package
  • #paths


191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'src/lib/installation/update_repository.rb', line 191

def fetch(path = Pathname("/download"))
  init_progress

  Dir.mktmpdir do |workdir|
    packages.each_with_index do |package, index|
      update_progress(100 * index / packages.size)
      fetch_and_extract_package(package, workdir)
    end
    @updates_file = build_squashfs(workdir, next_name(path, length: 3))
  end
rescue Y2Packager::PackageFetchError, Y2Packager::PackageExtractionError,
       CouldNotSquashPackage => e
  log.error("Could not fetch update: #{e.inspect}. Rolling back.")
  raise CouldNotFetchUpdate
end

#inspectString

Redefines the inspect method to avoid logging passwords

Returns:

  • (String)

    Debugging information



268
269
270
# File 'src/lib/installation/update_repository.rb', line 268

def inspect
  "#<Installation::UpdateRepository> @uri=\"#{safe_uri}\" @origin=#{@origin.inspect}"
end

#packagesArray<Y2Packager::Resolvable>

Retrieves the list of packages to unpack to the inst-sys

Only packages in the update repository are considered, meta-packages which should be used in an add-on and not applied to the inst-sys are ignored. The packages are sorted by name (alphabetical order). Additionally, only the latest version is considered.

Returns:

  • (Array<Y2Packager::Resolvable>)

    List of packages to install

See Also:

  • Y2Packager::Resolvable


153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'src/lib/installation/update_repository.rb', line 153

def packages
  return @packages unless @packages.nil?

  add_repo
  all_packages = Y2Packager::Resolvable.find(kind: :package, source: repo_id)
  pkg_names = all_packages.map(&:name).uniq

  # find the highest version of each package
  @packages = pkg_names.map do |name|
    all_packages.select { |p| p.name == name }.max do |a, b|
      Yast::Pkg.CompareVersions(a.version, b.version)
    end
  end
  log.info "Found #{@packages.size} packages: #{@packages.map(&:name)}"
  # remove packages which are used as addons, these should not be applied to the inst-sys
  addon_pkgs = Y2Packager::SelfUpdateAddonFilter.packages(repo_id)
  @packages.reject! { |p| addon_pkgs.include?(p.name) }
  log.info "Using #{@packages.size} packages: #{@packages.map(&:name)}"
  @packages
end

#remote?Boolean

Determines whether the URI of the repository is remote or not

Returns:

  • (Boolean)

    true if the repository is using a 'remote URI'; false otherwise.

See Also:

  • Pkg.UrlSchemeIsRemote


261
262
263
# File 'src/lib/installation/update_repository.rb', line 261

def remote?
  Yast::Pkg.UrlSchemeIsRemote(uri.scheme)
end

#user_defined?Boolean

Returns whether is a user defined repository

Returns:

  • (Boolean)

    true if the repository is user-defined empty; false otherwise.



251
252
253
# File 'src/lib/installation/update_repository.rb', line 251

def user_defined?
  origin == :user
end