mirror of
				https://github.com/GayPizzaSpecifications/darwin-apk.git
				synced 2025-11-04 07:59:38 +00:00 
			
		
		
		
	basic package graph implemented
This commit is contained in:
		@ -5,8 +5,16 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import Foundation
 | 
					import Foundation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal struct ApkRequirement {
 | 
					internal struct ApkRequirement: Hashable {
 | 
				
			||||||
  static func extract(blob extract: String) throws(ParseError) -> (String, ApkVersionSpecification) {
 | 
					  let name: String
 | 
				
			||||||
 | 
					  let versionSpec: ApkVersionSpecification
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  init(name: String, spec: ApkVersionSpecification) {
 | 
				
			||||||
 | 
					    self.name = name
 | 
				
			||||||
 | 
					    self.versionSpec = spec
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  init(extract: String) throws(ParseError) {
 | 
				
			||||||
    var comparer: ComparatorBits = []
 | 
					    var comparer: ComparatorBits = []
 | 
				
			||||||
    var dependStr = extract[...]
 | 
					    var dependStr = extract[...]
 | 
				
			||||||
    let nameEnd: String.Index, versionStart: String.Index
 | 
					    let nameEnd: String.Index, versionStart: String.Index
 | 
				
			||||||
@ -30,7 +38,7 @@ internal struct ApkRequirement {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      (nameEnd, versionStart) = (range.lowerBound, range.upperBound)
 | 
					      (nameEnd, versionStart) = (range.lowerBound, range.upperBound)
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      // 
 | 
					      // Lack of conflict flag indicates any version
 | 
				
			||||||
      if !comparer.contains(.conflict) {
 | 
					      if !comparer.contains(.conflict) {
 | 
				
			||||||
        comparer.formUnion(.any)
 | 
					        comparer.formUnion(.any)
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -38,9 +46,18 @@ internal struct ApkRequirement {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Parse version specification
 | 
					    // Parse version specification
 | 
				
			||||||
    let spec = try ApkVersionSpecification(comparer, version: dependStr[versionStart...])
 | 
					    self.versionSpec = try ApkVersionSpecification(comparer, version: dependStr[versionStart...])
 | 
				
			||||||
    let name = String(dependStr[..<nameEnd])
 | 
					    self.name = String(dependStr[..<nameEnd])
 | 
				
			||||||
    return (name, spec)
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extension ApkRequirement: CustomStringConvertible {
 | 
				
			||||||
 | 
					  var description: String {
 | 
				
			||||||
 | 
					    switch self.versionSpec {
 | 
				
			||||||
 | 
					    case .any: self.name
 | 
				
			||||||
 | 
					    case .conflict: "!\(self.name)"
 | 
				
			||||||
 | 
					    case .constraint(let op, let version): "\(self.name)\(op)\(version)"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										64
									
								
								Sources/apk/Graph/ApkPackageGraph.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								Sources/apk/Graph/ApkPackageGraph.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * darwin-apk © 2024 Gay Pizza Specifications
 | 
				
			||||||
 | 
					 * SPDX-License-Identifier: Apache-2.0
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ApkPackageGraph {
 | 
				
			||||||
 | 
					  let pkgIndex: ApkIndex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private var _nodes = [ApkPackageGraphNode]()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var nodes: [ApkPackageGraphNode] { self._nodes }
 | 
				
			||||||
 | 
					  var shallowIsolates: [ApkPackageGraphNode] { self._nodes.filter(\.parents.isEmpty) }
 | 
				
			||||||
 | 
					  var deepIsolates: [ApkPackageGraphNode] { self._nodes.filter(\.children.isEmpty) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  init(index: ApkIndex) {
 | 
				
			||||||
 | 
					    self.pkgIndex = index
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  func buildGraphNode() {
 | 
				
			||||||
 | 
					    var provides = [String: Int]()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (idx, package) in self.pkgIndex.packages.enumerated() {
 | 
				
			||||||
 | 
					      provides[package.name] = idx
 | 
				
			||||||
 | 
					      for provision in package.provides {
 | 
				
			||||||
 | 
					        provides[provision.name] = idx
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for package in pkgIndex.packages {
 | 
				
			||||||
 | 
					      self._nodes.append(.init(
 | 
				
			||||||
 | 
					        package: package,
 | 
				
			||||||
 | 
					        children: package.dependencies.compactMap { dependency in
 | 
				
			||||||
 | 
					          guard let id = provides[dependency.requirement.name] else {
 | 
				
			||||||
 | 
					            return nil
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          return .init(self, id: id, constraint: .dep(version: dependency.requirement.versionSpec))
 | 
				
			||||||
 | 
					        } + package.provides.compactMap { provision in
 | 
				
			||||||
 | 
					          guard let id = provides[provision.name] else {
 | 
				
			||||||
 | 
					            return nil
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          return .init(self, id: id, constraint: .provision)
 | 
				
			||||||
 | 
					        } + package.installIf.compactMap { installIf in
 | 
				
			||||||
 | 
					          guard let id = provides[installIf.requirement.name] else {
 | 
				
			||||||
 | 
					            return nil
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          return .init(self, id: id, constraint: .installIf(version: installIf.requirement.versionSpec ))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var reverseDependencies = [ApkIndexRequirementRef: [ApkIndexRequirementRef]]()
 | 
				
			||||||
 | 
					    for (index, node) in self._nodes.enumerated() {
 | 
				
			||||||
 | 
					      for child in node.children {
 | 
				
			||||||
 | 
					        reverseDependencies[child, default: []].append(
 | 
				
			||||||
 | 
					          .init(self, id: index, constraint: child.constraint)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (ref, parents) in reverseDependencies {
 | 
				
			||||||
 | 
					      self._nodes[ref.packageID].parents = parents
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										35
									
								
								Sources/apk/Graph/ApkPackageGraphNode.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								Sources/apk/Graph/ApkPackageGraphNode.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * darwin-apk © 2024 Gay Pizza Specifications
 | 
				
			||||||
 | 
					 * SPDX-License-Identifier: Apache-2.0
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Foundation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ApkPackageGraphNode {
 | 
				
			||||||
 | 
					  private weak var graph: ApkPackageGraph!
 | 
				
			||||||
 | 
					  let package: ApkIndexPackage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //private var _parents = NSHashTable<ApkPackageGraphNode>.weakObjects()
 | 
				
			||||||
 | 
					  //private var _children = NSHashTable<ApkPackageGraphNode>.weakObjects()
 | 
				
			||||||
 | 
					  var parents = [ApkIndexRequirementRef]()
 | 
				
			||||||
 | 
					  var children: [ApkIndexRequirementRef]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  internal init(package: ApkIndexPackage, children: [ApkIndexRequirementRef]) {
 | 
				
			||||||
 | 
					    self.package = package
 | 
				
			||||||
 | 
					    self.children = children
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extension ApkPackageGraphNode: CustomStringConvertible {
 | 
				
			||||||
 | 
					  var description: String {
 | 
				
			||||||
 | 
					    var result = "node[\(self.package.name)]"
 | 
				
			||||||
 | 
					    if !self.parents.isEmpty {
 | 
				
			||||||
 | 
					      result += ", parents[\(self.parents.lazy.map(\.description).joined(separator: ", "))]"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if !self.children.isEmpty {
 | 
				
			||||||
 | 
					      result += ", children[\(self.children.lazy.map(\.description).joined(separator: ", "))]"
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return result
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -5,22 +5,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import Foundation
 | 
					import Foundation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ApkIndexDependency: ApkIndexRequirementRef {
 | 
					struct ApkIndexDependency: Hashable {
 | 
				
			||||||
  let name: String
 | 
					  let requirement: ApkRequirement
 | 
				
			||||||
  let versionSpec: ApkVersionSpecification
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  init(name: String, version spec: ApkVersionSpecification) {
 | 
					  init(requirement: ApkRequirement) {
 | 
				
			||||||
    self.name = name
 | 
					    self.requirement = requirement
 | 
				
			||||||
    self.versionSpec = spec
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
extension ApkIndexDependency: CustomStringConvertible {
 | 
					 | 
				
			||||||
  var description: String {
 | 
					 | 
				
			||||||
    switch self.versionSpec {
 | 
					 | 
				
			||||||
    case .any: self.name
 | 
					 | 
				
			||||||
    case .conflict: "!\(self.name)"
 | 
					 | 
				
			||||||
    case .constraint(let op, let version): "\(self.name)\(op)\(version)"
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -3,12 +3,10 @@
 | 
				
			|||||||
 * SPDX-License-Identifier: Apache-2.0
 | 
					 * SPDX-License-Identifier: Apache-2.0
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ApkIndexInstallIf: ApkIndexRequirementRef {
 | 
					struct ApkIndexInstallIf: Hashable {
 | 
				
			||||||
  let name: String
 | 
					  let requirement: ApkRequirement
 | 
				
			||||||
  let versionSpec: ApkVersionSpecification
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  init(name: String, version spec: ApkVersionSpecification) {
 | 
					  init(requirement: ApkRequirement) {
 | 
				
			||||||
    self.name = name
 | 
					    self.requirement = requirement
 | 
				
			||||||
    self.versionSpec = spec
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -5,7 +5,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import Foundation
 | 
					import Foundation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ApkIndexPackage: ApkIndexRequirementRef {
 | 
					struct ApkIndexPackage: Hashable {
 | 
				
			||||||
  let indexChecksum: ApkIndexDigest
 | 
					  let indexChecksum: ApkIndexDigest
 | 
				
			||||||
  let name: String
 | 
					  let name: String
 | 
				
			||||||
  let version: String
 | 
					  let version: String
 | 
				
			||||||
@ -74,8 +74,10 @@ extension ApkIndexPackage {
 | 
				
			|||||||
      case "A":
 | 
					      case "A":
 | 
				
			||||||
        architecture = record.value
 | 
					        architecture = record.value
 | 
				
			||||||
      case "D":
 | 
					      case "D":
 | 
				
			||||||
        do { dependencies = try ApkIndexDependency.extract(record.value) }
 | 
					        do {
 | 
				
			||||||
        catch { throw .badValue(key: record.key) }
 | 
					          dependencies = try record.value.components(separatedBy: " ")
 | 
				
			||||||
 | 
					            .map { .init(requirement: try .init(extract: $0)) }
 | 
				
			||||||
 | 
					        } catch { throw .badValue(key: record.key) }
 | 
				
			||||||
      case "C":
 | 
					      case "C":
 | 
				
			||||||
        guard let digest = ApkIndexDigest(decode: record.value) else {
 | 
					        guard let digest = ApkIndexDigest(decode: record.value) else {
 | 
				
			||||||
          throw .badValue(key: record.key)
 | 
					          throw .badValue(key: record.key)
 | 
				
			||||||
@ -92,11 +94,15 @@ extension ApkIndexPackage {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        installedSize = value
 | 
					        installedSize = value
 | 
				
			||||||
      case "p":
 | 
					      case "p":
 | 
				
			||||||
        do { provides = try ApkIndexProvides.extract(record.value) }
 | 
					        do {
 | 
				
			||||||
        catch { throw .badValue(key: record.key) }
 | 
					          provides = try record.value.components(separatedBy: " ")
 | 
				
			||||||
 | 
					            .map { .init(requirement: try .init(extract: $0)) }
 | 
				
			||||||
 | 
					        } catch { throw .badValue(key: record.key) }
 | 
				
			||||||
      case "i":
 | 
					      case "i":
 | 
				
			||||||
        do { installIf = try ApkIndexInstallIf.extract(record.value) }
 | 
					        do {
 | 
				
			||||||
        catch { throw .badValue(key: record.key) }
 | 
					          installIf = try record.value.components(separatedBy: " ")
 | 
				
			||||||
 | 
					            .map { .init(requirement: try .init(extract: $0)) }
 | 
				
			||||||
 | 
					        } catch { throw .badValue(key: record.key) }
 | 
				
			||||||
      case "o":
 | 
					      case "o":
 | 
				
			||||||
        origin = record.value
 | 
					        origin = record.value
 | 
				
			||||||
      case "m":
 | 
					      case "m":
 | 
				
			||||||
@ -191,13 +197,13 @@ extension ApkIndexPackage: CustomStringConvertible {
 | 
				
			|||||||
    s += "provider prio:  \(providerPrio)\n"
 | 
					    s += "provider prio:  \(providerPrio)\n"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if !self.dependencies.isEmpty {
 | 
					    if !self.dependencies.isEmpty {
 | 
				
			||||||
    s += "dependencies: - \(self.dependencies.map(String.init).joined(separator: " "))\n"
 | 
					    s += "dependencies: - \(self.dependencies.map(\.requirement.description).joined(separator: " "))\n"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if !self.provides.isEmpty {
 | 
					    if !self.provides.isEmpty {
 | 
				
			||||||
    s += "provides: ----- \(self.provides.map { $0.name }.joined(separator: " "))\n"
 | 
					    s += "provides: ----- \(self.provides.map(\.name).joined(separator: " "))\n"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if !self.installIf.isEmpty {
 | 
					    if !self.installIf.isEmpty {
 | 
				
			||||||
    s += "install if: --- \(self.installIf.map { $0.name }.joined(separator: " "))\n"
 | 
					    s += "install if: --- \(self.installIf.map(\.requirement.description).joined(separator: " "))\n"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return s
 | 
					    return s
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -3,10 +3,10 @@
 | 
				
			|||||||
 * SPDX-License-Identifier: Apache-2.0
 | 
					 * SPDX-License-Identifier: Apache-2.0
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ApkIndexProvides: ApkIndexRequirementRef {
 | 
					struct ApkIndexProvides: Hashable {
 | 
				
			||||||
  let name: String
 | 
					  let name: String
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  init(name: String, version _: ApkVersionSpecification) {
 | 
					  init(requirement: ApkRequirement) {
 | 
				
			||||||
    self.name = name
 | 
					    self.name = requirement.name
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -3,24 +3,58 @@
 | 
				
			|||||||
 * SPDX-License-Identifier: Apache-2.0
 | 
					 * SPDX-License-Identifier: Apache-2.0
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protocol ApkIndexRequirementRef: Equatable, Hashable {
 | 
					struct ApkIndexRequirementRef {
 | 
				
			||||||
  var name: String { get }
 | 
					  private weak var _graph: ApkPackageGraph?
 | 
				
			||||||
  var invert: Bool { get }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  init(name: String, version spec: ApkVersionSpecification)
 | 
					  let packageID: Int
 | 
				
			||||||
 | 
					  let constraint: Constraint
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  func satisfied(by other: ApkIndexPackage) -> Bool
 | 
					  init(_ graph: ApkPackageGraph, id: Int, constraint: Constraint) {
 | 
				
			||||||
 | 
					    self._graph = graph
 | 
				
			||||||
 | 
					    self.packageID = id
 | 
				
			||||||
 | 
					    self.constraint = constraint
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var package: ApkIndexPackage {
 | 
				
			||||||
 | 
					    self._graph!.pkgIndex.packages[self.packageID]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  func satisfied(by other: ApkRequirement) -> Bool {
 | 
				
			||||||
 | 
					    true
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extension ApkIndexRequirementRef: Equatable, Hashable {
 | 
				
			||||||
 | 
					  static func == (lhs: Self, rhs: Self) -> Bool {
 | 
				
			||||||
 | 
					    lhs.packageID == rhs.packageID && lhs.constraint == rhs.constraint
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  func hash(into hasher: inout Hasher) {
 | 
				
			||||||
 | 
					    self.packageID.hash(into: &hasher)
 | 
				
			||||||
 | 
					    self.constraint.hash(into: &hasher)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extension ApkIndexRequirementRef {
 | 
					extension ApkIndexRequirementRef {
 | 
				
			||||||
  var invert: Bool { false }
 | 
					  enum Constraint: Hashable {
 | 
				
			||||||
  func satisfied(by _: ApkIndexPackage) -> Bool { true }
 | 
					    case dep(version: ApkVersionSpecification)
 | 
				
			||||||
 | 
					    case provision
 | 
				
			||||||
  static func extract<T: ApkIndexRequirementRef>(_ blob: String) throws(ApkRequirement.ParseError) -> [T] {
 | 
					    case installIf(version: ApkVersionSpecification)
 | 
				
			||||||
    return try blob.components(separatedBy: " ")
 | 
					  }
 | 
				
			||||||
      .map { token throws(ApkRequirement.ParseError) in
 | 
					}
 | 
				
			||||||
        let (name, versionSpec) = try ApkRequirement.extract(blob: token)
 | 
					
 | 
				
			||||||
        return .init(name: name, version: versionSpec)
 | 
					extension ApkIndexRequirementRef: CustomStringConvertible {
 | 
				
			||||||
      }
 | 
					  var description: String {
 | 
				
			||||||
 | 
					    guard let package = self._graph?.pkgIndex.packages[self.packageID] else {
 | 
				
			||||||
 | 
					      return String()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return switch self.constraint {
 | 
				
			||||||
 | 
					    case .dep(let version):
 | 
				
			||||||
 | 
					      "dep=\(ApkRequirement(name: package.name, spec: version))"
 | 
				
			||||||
 | 
					    case .provision:
 | 
				
			||||||
 | 
					      "provides=\(package.name)"
 | 
				
			||||||
 | 
					    case .installIf(let version):
 | 
				
			||||||
 | 
					      "installIf=\(ApkRequirement(name: package.name, spec: version))"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -13,11 +13,11 @@ public struct ApkIndexUpdater {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  public init() {
 | 
					  public init() {
 | 
				
			||||||
    self.repositories = [
 | 
					    self.repositories = [
 | 
				
			||||||
      "https://dl-cdn.alpinelinux.org/alpine/v3.21/main",
 | 
					      "https://dl-cdn.alpinelinux.org/alpine/v3.20/main",
 | 
				
			||||||
      "https://dl-cdn.alpinelinux.org/alpine/edge/community"
 | 
					      "https://dl-cdn.alpinelinux.org/alpine/v3.20/community"
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
    // other archs: "armhf", "armv7", "loongarch64", "ppc64le", "riscv64", "s390x", "x86"
 | 
					    // other archs: "armhf", "armv7", "loongarch64", "ppc64le", "riscv64", "s390x", "x86"
 | 
				
			||||||
    self.architectures = [ "aarch64", "x86_64" ]
 | 
					    self.architectures = [ "aarch64" /*, "x86_64" */ ]
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public func update() {
 | 
					  public func update() {
 | 
				
			||||||
@ -41,14 +41,23 @@ public struct ApkIndexUpdater {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let index: ApkIndex
 | 
					    let graph: ApkPackageGraph
 | 
				
			||||||
    do {
 | 
					    do {
 | 
				
			||||||
      let tables = try repositories.map { try readIndex(URL(filePath: $0.localName)) }
 | 
					      let tables = try repositories.map { try readIndex(URL(filePath: $0.localName)) }
 | 
				
			||||||
      index = ApkIndex.merge(tables)
 | 
					      graph = ApkPackageGraph(index: ApkIndex.merge(tables))
 | 
				
			||||||
      try index.description.write(to: URL(fileURLWithPath: "packages.txt"), atomically: false, encoding: .utf8)
 | 
					      graph.buildGraphNode()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      try graph.pkgIndex.description.write(to: URL(filePath: "packages.txt"), atomically: false, encoding: .utf8)
 | 
				
			||||||
    } catch {
 | 
					    } catch {
 | 
				
			||||||
      fatalError(error.localizedDescription)
 | 
					      fatalError(error.localizedDescription)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if var out = TextFileWriter(URL(filePath: "shallowIsolates.txt")) {
 | 
				
			||||||
 | 
					      for node in graph.shallowIsolates { print(node, to: &out) }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if var out = TextFileWriter(URL(filePath: "deepIsolates.txt")) {
 | 
				
			||||||
 | 
					      for node in graph.deepIsolates { print(node, to: &out) }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private func readIndex(_ indexURL: URL) throws -> ApkIndex {
 | 
					  private func readIndex(_ indexURL: URL) throws -> ApkIndex {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										28
									
								
								Sources/apk/Utility/TextFileWriter.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								Sources/apk/Utility/TextFileWriter.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * darwin-apk © 2024 Gay Pizza Specifications
 | 
				
			||||||
 | 
					 * SPDX-License-Identifier: Apache-2.0
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Foundation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct TextFileWriter: TextOutputStream {
 | 
				
			||||||
 | 
					  private var _hnd: FileHandle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  init?(_ to: URL) {
 | 
				
			||||||
 | 
					    let file = open(to.path(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, 0o644)
 | 
				
			||||||
 | 
					    guard file >= 0 else {
 | 
				
			||||||
 | 
					      return nil
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    self._hnd = FileHandle(fileDescriptor: file, closeOnDealloc: true)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mutating func write(_ string: String) {
 | 
				
			||||||
 | 
					    if let data = string.data(using: .utf8) {
 | 
				
			||||||
 | 
					      try? self._hnd.write(contentsOf: data)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mutating func close() throws {
 | 
				
			||||||
 | 
					    try self._hnd.close()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user