mirror of
https://github.com/NixOS/mobile-nixos.git
synced 2024-12-18 13:31:36 +03:00
7dff001d75
This ensures graphical progress is shown ASAP when dependencies are equally likely to run. Otherwise, when the graphical step was ready, and switchroot about to run, the shell step could run before the splash. This means that, in practice, a long running task like e2fsck could have prevented the splash to show. It doesn't make sense to make the other tasks depend on a splash task! There is no intention to implement any other special-cased ordering. If there is the need to, it might mean that there is a deficiency in the design.
134 lines
3.3 KiB
Ruby
134 lines
3.3 KiB
Ruby
# Namespace where tasks can be defined, and hosting methods harmonizing a run.
|
|
module Tasks
|
|
# Register a singleton task to be instantiated and ran.
|
|
# @internal
|
|
def self.register_singleton(klass)
|
|
$logger.debug("Task #{klass.name} registered...")
|
|
@singletons_to_be_instantiated ||= []
|
|
@singletons_to_be_instantiated << klass
|
|
end
|
|
|
|
# Register one task to be ran.
|
|
def self.register(task)
|
|
$logger.debug("Task #{task.name} registered...")
|
|
@tasks ||= []
|
|
@tasks << task
|
|
end
|
|
|
|
# Tries to run *all* tasks.
|
|
def self.go()
|
|
# Registers tasks that still needs to be instantiated
|
|
@singletons_to_be_instantiated.each do |klass|
|
|
# Their mere existence registers them.
|
|
klass.instance
|
|
end
|
|
@singletons_to_be_instantiated = []
|
|
|
|
# Sort tasks to reduce the amount of loops it needs to fulfill them all.
|
|
# It's only a reduction due to files, mounts and devices being
|
|
# unpredictable!
|
|
@tasks.sort!
|
|
|
|
until @tasks.all?(&:ran) do
|
|
$logger.debug("Tasks resolution loop start")
|
|
@tasks
|
|
.reject(&:ran)
|
|
.each do |task|
|
|
task._try_run_task
|
|
end
|
|
# Don't burn the CPU
|
|
sleep(0.1)
|
|
end
|
|
end
|
|
end
|
|
|
|
# Basic task class.
|
|
class Task
|
|
attr_reader :ran
|
|
|
|
def self.new(*args)
|
|
$logger.debug("New instance of #{self.name}...")
|
|
$logger.debug(" -> #{args.inspect}")
|
|
instance = super(*args)
|
|
Tasks.register(instance)
|
|
instance
|
|
end
|
|
|
|
def name
|
|
self.class.name
|
|
end
|
|
|
|
def self.inherited(subclass)
|
|
$logger.debug("#{subclass.name} created...")
|
|
end
|
|
|
|
# Sort first by dependencies, then by name, then by object_id
|
|
# (for stable sort order)
|
|
def <=>(other)
|
|
return -1 if other.depends_on?(self)
|
|
return 1 if depends_on?(other)
|
|
|
|
by_ux_priority = ux_priority <=> other.ux_priority
|
|
return by_ux_priority unless by_ux_priority == 0
|
|
|
|
by_name = name <=> other.name
|
|
return by_name unless by_name == 0
|
|
|
|
object_id <=> other.object_id
|
|
end
|
|
|
|
def depends_on?(other)
|
|
dependencies.any? do |dependency|
|
|
dependency.depends_on?(other)
|
|
end
|
|
end
|
|
|
|
def add_dependency(kind, *args)
|
|
raise NameError.new("No dependency named #{kind}") unless Dependencies.constants.include?(kind.to_sym)
|
|
dependencies << Dependencies.const_get(kind.to_sym).new(*args)
|
|
end
|
|
|
|
def dependencies_fulfilled?()
|
|
dependencies.all?(&:fulfilled?)
|
|
end
|
|
|
|
# Internal actual way to run the task
|
|
# This runs the `#run` method.
|
|
def _try_run_task()
|
|
$logger.debug("Looking to run task #{name}...")
|
|
return unless dependencies_fulfilled?
|
|
unless @ran
|
|
$logger.info("Running #{name}...")
|
|
run()
|
|
$logger.debug("Finished #{name}...")
|
|
@ran = true
|
|
end
|
|
end
|
|
|
|
def dependencies()
|
|
@dependencies ||= []
|
|
@dependencies
|
|
end
|
|
|
|
# This allows a task to be ordered before other tasks, because it is used to
|
|
# enhance the UX of the boot process. Assume this will be compared with +<=>+.
|
|
# This should seldom be used, and mainly for tasks that show the progress of
|
|
# the boot process.
|
|
# (For internal use.)
|
|
# @internal
|
|
def ux_priority()
|
|
0
|
|
end
|
|
end
|
|
|
|
# A task that can only have one instance.
|
|
class SingletonTask < Task
|
|
include Singleton
|
|
|
|
def self.inherited(subclass)
|
|
super
|
|
# Delay initializing, as right now we have an fresh new empty class.
|
|
Tasks.register_singleton(subclass)
|
|
end
|
|
end
|