From e458df0afdd3f48cc4683188b709ab5c55d2bbb4 Mon Sep 17 00:00:00 2001 From: Luka Vandervelden Date: Sat, 2 Nov 2019 20:59:08 +0100 Subject: [PATCH] Various. --- src/package.cr | 2 +- src/package/configuration.cr | 29 +++++++++++++ src/package/context.cr | 82 +++++++++++++++++++++++++++++++++--- src/package/database.cr | 7 ++- src/package/package.cr | 47 +++++++++++++++++++-- src/package/repository.cr | 35 +++++++++++++++ 6 files changed, 190 insertions(+), 12 deletions(-) create mode 100644 src/package/configuration.cr create mode 100644 src/package/repository.cr diff --git a/src/package.cr b/src/package.cr index 88ef9d7..f67f6dd 100644 --- a/src/package.cr +++ b/src/package.cr @@ -23,7 +23,7 @@ args.shift begin case command when "add" - context.install args + context.install args.map { |s| Package::Atom.from_string s } when "remove" context.remove args.map { |s| Package::Atom.from_string s } end diff --git a/src/package/configuration.cr b/src/package/configuration.cr new file mode 100644 index 0000000..1ada1a0 --- /dev/null +++ b/src/package/configuration.cr @@ -0,0 +1,29 @@ +require "specparser" + +class Package::Configuration + PATH_FROM_ROOT = "/etc/package.cfg" + + getter file_path : String? + + getter repositories = Array(Repository).new + + getter cache_directory = "/var/cache/package" + + def initialize + end + + def initialize(@file_path : String) + specs = SpecParser.parse File.read @file_path.not_nil! + + specs.sections.each do |section| + case section.name + when "repository" + @repositories << Repository.new( + File.read("#{section.options[0]}/repository.spec"), + section.options[0] + ) + end + end + end +end + diff --git a/src/package/context.cr b/src/package/context.cr index 11d30d3..2797a30 100644 --- a/src/package/context.cr +++ b/src/package/context.cr @@ -1,10 +1,13 @@ require "colorize" require "uuid" require "file_utils" +require "uri" require "../io.cr" require "./weird.cr" +require "./configuration.cr" +require "./repository.cr" class Package::Context < Weird::Context property root = "/" @@ -12,12 +15,16 @@ class Package::Context < Weird::Context # Stores informations about already installed packages, their # manifests, and so on. @database = Database.new + @configuration = Configuration.new + @cache_directory = "/var/cache/package" def initialize() + self.root = "/" end def root=(@root) @database.root = "#{@root}#{Database::PATH_FROM_ROOT}" + @configuration = Configuration.new "#{@root}#{Configuration::PATH_FROM_ROOT}" end def install(package : Package, data_directory : String) @@ -81,11 +88,71 @@ class Package::Context < Weird::Context install [file] end def install(atoms : Array(Atom)) + unchecked_atoms = Deque.new atoms + packages_to_install = Array(Tuple(Repository, Package)).new + + while unchecked_atoms.size > 0 + atom = unchecked_atoms.pop + + tuple = get_installable atom + + if tuple.nil? + raise Exception.new "Could not find '#{atom}'." + end + + packages_to_install << tuple + + _, package = tuple + + package.dependencies.each do |atom| + unless is_installed? atom + unchecked_atoms.push atom + end + end + end + + #pp! packages_to_install.map &.[1].to_atom.to_s + + packages_to_install.reverse.each do |tuple| + download tuple + end + + # FIXME: Install everything here. + packages_to_install.reverse.each do |tuple| + repository, package = tuple + + url = "#{repository.url}/#{package.file_path}" + + install url + end end def install(atom : Atom) install [atom] end def upgrade(atom : Atom) + warning "(unimplemented) upgrade(Atom)" + end + + # XXX: Unimplemented. + def download(tuple : Tuple(Repository, Package)) + repository, package = tuple + + uri = URI.parse package.file_path + + if uri.scheme == "http" || uri.scheme == "https" + FileUtils.mkdir_p @cache_directory + + pp package.file_path + #File.write HTTP::Client.get + end + end + + def get_installable(atom : Atom) + @configuration.repositories.each do |repository| + match = repository.find &.matches?(atom) + + return {repository, match} if match + end end def remove(packages : Array(Package)) @@ -106,14 +173,13 @@ class Package::Context < Weird::Context packages_to_remove << package all_packages - .select do |p| - p.dependencies.any? do |dependency| - # FIXME: Check full atoms and not just names. + .select(&.dependencies.any? do |dependency| + # FIXME: Check full atoms and not just names. - # FIXME: Checking there’s no collision with world files is probably done around here. - packages_to_remove.find &.name.==(dependency) - end - end + # FIXME: Checking there’s no collision with world files is probably done around here. + + packages_to_remove.find &.matches? dependency + end) .each do |p| if unchecked_packages.find &.==(p) next @@ -130,6 +196,8 @@ class Package::Context < Weird::Context packages_to_remove.reverse.each do |package| manifest = @database.get_manifest package + info "Removing '#{package.to_atom.to_s}'" + manifest.reverse.each do |entry| if entry.type == "directory" && (!Dir.exists?(entry.file) || !Dir.empty?(entry.file)) next diff --git a/src/package/database.cr b/src/package/database.cr index cba6330..0c4a67d 100644 --- a/src/package/database.cr +++ b/src/package/database.cr @@ -28,7 +28,12 @@ class Package::Database end def is_installed?(atom : Atom) - Dir.exists? get_entry_path(atom) + if atom.slot.nil? + Dir.exists?(get_entry_path(atom)) && + Dir.children(get_entry_path(atom)).size > 0 + else + Dir.exists? get_entry_path(atom) + end end def get_package(atom : Atom) diff --git a/src/package/package.cr b/src/package/package.cr index 7141bfb..a56395f 100644 --- a/src/package/package.cr +++ b/src/package/package.cr @@ -8,7 +8,7 @@ class Package::Package getter release : Int32 getter slot : String - getter dependencies = Array(String).new + getter dependencies = Array(Atom).new getter file_path : String @@ -31,7 +31,9 @@ class Package::Package when "slot" slot = value.as_s when "dependencies" - @dependencies = value.as_a_or_s + @dependencies = value.as_a_or_s.map do |s| + Atom.from_string s + end end end @@ -41,9 +43,48 @@ class Package::Package @slot = slot.not_nil! end + def initialize(section : SpecParser::Section) + @file_path, @name, @version, release, @slot = section.options[0].split " " + @release = release.to_i + + section.content.each do |key, value| + case key + when "dependencies" + @dependencies = value.as_a_or_s.map do |s| + Atom.from_string s + end + end + end + end + def to_atom Atom.new @name, slot: @slot end + def matches?(atom : Atom) + return false unless @name == atom.name + + if slot = atom.slot + return false unless @slot == atom.slot + end + + true + end + + # Returns Array({package, file_name}) + def self.parse_repository_index(file_path : String) : Array(Package) + output = Array(Tuple(Package, String)).new + specs = SpecParser.parse File.read file_path + + specs.sections.each do |section| + case section.name + when "package" + package = Package.new section + + output << {package, file_name} + end + end + + output + end end - diff --git a/src/package/repository.cr b/src/package/repository.cr new file mode 100644 index 0000000..7335829 --- /dev/null +++ b/src/package/repository.cr @@ -0,0 +1,35 @@ +require "specparser" + +require "./exception.cr" + +class Package::Package + def initialize(section : SpecParser::Section) + @file_name, @name, @version, release, @slot = section.options[0].split " " + @release = release.to_i + + section.content.each do |key, value| + case key + when "dependencies" + @dependencies = value.as_a_or_s + end + end + end +end + +class Package::Repository < Array(Package::Package) + getter url : String + + def initialize(index_body : String, @url) + initialize + + specs = SpecParser.parse index_body + + specs.sections.each do |section| + case section.name + when "package" + self << ::Package::Package.new section + end + end + end +end +