mirror of
				https://github.com/GayPizzaSpecifications/darwin-apk.git
				synced 2025-11-04 07:59:38 +00:00 
			
		
		
		
	fix package graph
This commit is contained in:
		@ -24,33 +24,27 @@ public class ApkPackageGraph {
 | 
			
		||||
    for (idx, package) in self.pkgIndex.packages.enumerated() {
 | 
			
		||||
      provides[package.name] = idx
 | 
			
		||||
      for provision in package.provides {
 | 
			
		||||
        provides[provision.name] = idx
 | 
			
		||||
        if !provides.keys.contains(provision.name) {
 | 
			
		||||
          provides[provision.name] = idx
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (id, package) in pkgIndex.packages.enumerated() {
 | 
			
		||||
      let children: [ApkIndexRequirementRef] = package.dependencies.filter { dependency in dependency.requirement.versionSpec != .conflict }.compactMap { dependency in
 | 
			
		||||
        guard let id = provides[dependency.requirement.name] else {
 | 
			
		||||
          return nil
 | 
			
		||||
        }
 | 
			
		||||
        return .init(self, id: id, constraint: .dep(version: dependency.requirement.versionSpec))
 | 
			
		||||
      }
 | 
			
		||||
      self._nodes.append(.init(self,
 | 
			
		||||
        id: id,
 | 
			
		||||
        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 ))
 | 
			
		||||
        }
 | 
			
		||||
        children: children
 | 
			
		||||
      ))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var reverseDependencies = [ApkIndexRequirementRef: [ApkIndexRequirementRef]]()
 | 
			
		||||
    
 | 
			
		||||
    for (index, node) in self._nodes.enumerated() {
 | 
			
		||||
      for child in node.children {
 | 
			
		||||
        reverseDependencies[child, default: []].append(
 | 
			
		||||
@ -60,6 +54,7 @@ public class ApkPackageGraph {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (ref, parents) in reverseDependencies {
 | 
			
		||||
      let package = self._nodes[ref.packageID].package
 | 
			
		||||
      self._nodes[ref.packageID].parents = parents
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@ -67,30 +62,31 @@ public class ApkPackageGraph {
 | 
			
		||||
 | 
			
		||||
extension ApkPackageGraph {
 | 
			
		||||
  func findDependencyCycle(node: ApkPackageGraphNode) -> (ApkPackageGraphNode, ApkPackageGraphNode)? {
 | 
			
		||||
    var resolving = Set<ApkPackageGraphNode>()
 | 
			
		||||
    var visited = Set<ApkPackageGraphNode>()
 | 
			
		||||
    var resolving = Set<Int>()
 | 
			
		||||
    var visited = Set<Int>()
 | 
			
		||||
    return self.findDependencyCycle(node: node, &resolving, &visited)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  func findDependencyCycle(
 | 
			
		||||
    node: ApkPackageGraphNode,
 | 
			
		||||
    _ resolving: inout Set<ApkPackageGraphNode>,
 | 
			
		||||
    _ visited: inout Set<ApkPackageGraphNode>
 | 
			
		||||
    _ resolving: inout Set<Int>,
 | 
			
		||||
    _ visited: inout Set<Int>
 | 
			
		||||
  ) -> (ApkPackageGraphNode, ApkPackageGraphNode)? {
 | 
			
		||||
    for dependency in node.children {
 | 
			
		||||
      let depNode = self._nodes[dependency.packageID]
 | 
			
		||||
      if resolving.contains(depNode) {
 | 
			
		||||
      if resolving.contains(depNode.packageID) {
 | 
			
		||||
        print("VIA \(resolving.map({ self._nodes[$0].package.name } )) CYCLE \(node.package.name) \(depNode.package.name)")
 | 
			
		||||
        return (node, depNode)
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if !visited.contains(depNode) {
 | 
			
		||||
        resolving.insert(depNode)
 | 
			
		||||
      if !visited.contains(depNode.packageID) {
 | 
			
		||||
        resolving.insert(depNode.packageID)
 | 
			
		||||
        if let cycle = findDependencyCycle(node: depNode, &resolving, &visited) {
 | 
			
		||||
          return cycle
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        resolving.remove(depNode)
 | 
			
		||||
        visited.insert(depNode)
 | 
			
		||||
        resolving.remove(depNode.packageID)
 | 
			
		||||
        visited.insert(depNode.packageID)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -121,12 +117,13 @@ extension ApkPackageGraph {
 | 
			
		||||
      working[$0] = .init()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while true {
 | 
			
		||||
    while !working.isEmpty {
 | 
			
		||||
      // Set of all nodes now with satisfied dependencies
 | 
			
		||||
      var set = working
 | 
			
		||||
        .filter { _, children in children.isEmpty }
 | 
			
		||||
        .map(\.key)
 | 
			
		||||
 | 
			
		||||
      
 | 
			
		||||
      print("set \(set.count) working \(working.count)")
 | 
			
		||||
      // If nothing was satisfied in this loop, check for cycles
 | 
			
		||||
      // If no cycles exist and the working set is empty, resolve is complete
 | 
			
		||||
      if set.isEmpty {
 | 
			
		||||
@ -137,18 +134,21 @@ extension ApkPackageGraph {
 | 
			
		||||
        let cycles = working.keys.compactMap { node in
 | 
			
		||||
          self.findDependencyCycle(node: node)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        // Error if cycle breaking is turned off
 | 
			
		||||
        if !breakCycles {
 | 
			
		||||
          throw .cyclicDependency(cycles: cycles.map { node, dependency in
 | 
			
		||||
              "\(node) -> \(dependency)"
 | 
			
		||||
            }.joined(separator: "\n"))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Bread cycles by setting the new resolution set to dependencies that cycled
 | 
			
		||||
        set = cycles.map(\.1)
 | 
			
		||||
        
 | 
			
		||||
        // Break cycles by setting the new resolution set to dependencies that cycled
 | 
			
		||||
        set = cycles.flatMap { [$0.0, $0.1] }
 | 
			
		||||
        set = Array(Set(set))
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      
 | 
			
		||||
      print(set.map({ $0.package.name + " " + String($0.packageID) }))
 | 
			
		||||
      
 | 
			
		||||
      // Add installation set to list of installation sets
 | 
			
		||||
      results.append(set)
 | 
			
		||||
 | 
			
		||||
@ -158,10 +158,12 @@ extension ApkPackageGraph {
 | 
			
		||||
      }.reduce(into: [ApkPackageGraphNode: Set<ApkPackageGraphNode>]()) { d, node in
 | 
			
		||||
        d[node.key] = node.value.subtracting(set)
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      for (what, deps) in working {
 | 
			
		||||
        print("\(what.packageID) \(what.package.name): \(deps.map { $0.package.name + " " + String($0.packageID) })")
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    print(working)
 | 
			
		||||
 | 
			
		||||
    return results
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -22,6 +22,10 @@ struct ApkIndexRequirementRef {
 | 
			
		||||
  func satisfied(by other: ApkVersionRequirement) -> Bool {
 | 
			
		||||
    true
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  func normalize() -> ApkIndexRequirementRef {
 | 
			
		||||
    .init(self._graph!, id: self.packageID, constraint: .dep(version: .any))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extension ApkIndexRequirementRef: Equatable, Hashable {
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user