     /// The path of the workspace data.
     public let dataPath: AbsolutePath
 
+    /// The current state of managed dependencies.
+    public let managedDependencies: ManagedDependencies
+
+    /// The Pins store. The pins file will be created when first pin is added to pins store.
+    public let pinsStore: LoadableResult<PinsStore>
+
     /// The path for working repository clones (checkouts).
     let checkoutsPath: AbsolutePath
 

            }
        }
    }

    /// Returns the location of the dependency.
    ///
    /// Checkout dependencies will return the subpath inside `checkoutsPath` and
    /// edited dependencies will either return a subpath inside `editablesPath` or
    /// a custom path.
    private func path(for dependency: ManagedDependency) -> AbsolutePath {
        switch dependency.state {
        case .checkout:
            return checkoutsPath.appending(dependency.subpath)
        case .edited(let path):
            return path ?? editablesPath.appending(dependency.subpath)
        }
    }

    /// Fetch and load the complete package at the given path.
    ///
    /// This will implicitly cause any dependencies not yet present in the
    /// working checkouts to be resolved, cloned, and checked out.
    ///
    /// When fetching additional dependencies, the existing checkout versions
    /// will never be re-bound (or even re-fetched) as a result of this
    /// operation. This implies that the resulting local state may not match
    /// what would be computed from a fresh clone, but this makes for a more
    /// consistent command line development experience.
    ///
    /// - Returns: The loaded package graph.
    @discardableResult
    public func loadPackageGraph(
        root: WorkspaceRoot,
        diagnostics: DiagnosticsEngine,
        createMultipleTestProducts: Bool = false
    ) -> PackageGraph {
        // Ensure the cache path exists and validate that edited dependencies.
        createCacheDirectories(diagnostics: diagnostics)

        // Load the root manifests and currently checked out manifests.
        let rootManifests = loadRootManifests(packages: root.packages, diagnostics: diagnostics) 

        // Load the current manifests.
        let graphRoot = PackageGraphRoot(manifests: rootManifests, dependencies: root.dependencies)
        let currentManifests = loadDependencyManifests(root: graphRoot, diagnostics: diagnostics)

        // Compute the missing URLs.
        let missingURLs = currentManifests.missingURLs()

        // When loading current package graph, we can't use the diagnostic
        // engine passed by clients because we will end up adding diagnostics
        // which might go away after a complete loading.
        let partialDiagnostics = DiagnosticsEngine()

        // Load the current package graph.
        let currentGraph = PackageGraphLoader().load(
            root: PackageGraphRoot(manifests: rootManifests, dependencies: root.dependencies),
            externalManifests: currentManifests.dependencies.map({ $0.manifest }),
            diagnostics: partialDiagnostics,
            fileSystem: fileSystem,
            shouldCreateMultipleTestProducts: createMultipleTestProducts)

        // If there are no missing URLs or if we encountered some errors, return the current graph.
        if diagnostics.hasErrors || missingURLs.isEmpty {
            // FIXME: Add API to append one engine to another.
            for diag in partialDiagnostics.diagnostics {
                diagnostics.emit(data: diag.data, location: diag.location)
            }
            return currentGraph
        }

        // Start by informing the delegate of what is happening.
        delegate.packageGraphWillLoad(
            currentGraph: currentGraph,
            dependencies: managedDependencies.values,
            missingURLs: missingURLs)

        var updatedManifests: DependencyManifests? = nil

        resolve: do {
            // Load the pins store.
            guard let pinsStore = diagnostics.wrap({ try pinsStore.load() }) else {
                break resolve
            }

            // Create the constraints.
            var constraints = [RepositoryPackageConstraint]()
            constraints += rootManifests.flatMap({ $0.package.dependencyConstraints() })
            constraints += root.constraints

            var pins = [RepositoryPackageConstraint]()
            pins += pinsStore.createConstraints()
            pins += currentManifests.createDependencyConstraints()

            // Perform dependency resolution.
            let result = resolveDependencies(dependencies: constraints, pins: pins, diagnostics: diagnostics)
            guard !diagnostics.hasErrors else { break resolve }

            // Update the checkouts with dependency resolution result.
            try updateCheckouts(with: result)

            // Load the updated manifests.
            updatedManifests = loadDependencyManifests(root: graphRoot, diagnostics: diagnostics)

            // If autopin is enabled, reset and pin everything.
            if pinsStore.isAutoPinEnabled && !diagnostics.hasErrors {
                try self.pinAll(
                     pinsStore: pinsStore,
                     dependencyManifests: updatedManifests!,
                     reset: true)
            }
        } catch {
            diagnostics.emit(error)
        }

        return PackageGraphLoader().load(
            root: PackageGraphRoot(manifests: rootManifests, dependencies: root.dependencies),
            externalManifests: updatedManifests?.dependencies.map({ $0.manifest }) ?? [],
            diagnostics: diagnostics,
            fileSystem: fileSystem,
            shouldCreateMultipleTestProducts: createMultipleTestProducts
        )
    }

	/// Load the package graph data.
	///
	/// This method returns the package graph, and the mapping between each
	/// package and its corresponding managed dependency.
	///
	/// The current managed dependencies will be reported via the delegate
	/// before and after loading the package graph.
    public func loadGraphData(
        root: WorkspaceRoot,
        diagnostics: DiagnosticsEngine,
        createMultipleTestProducts: Bool = false
    ) -> (graph: PackageGraph, dependencyMap: [ResolvedPackage: ManagedDependency]) {

        // Load the package graph.
        let graph = loadPackageGraph(
            root: root, diagnostics: diagnostics, createMultipleTestProducts: createMultipleTestProducts)

        // Report the updated managed dependencies.
        delegate.managedDependenciesDidUpdate(managedDependencies.values)

        // Create the dependency map by associating each resolved package with its corresponding managed dependency.
        let managedDependenciesByName = Dictionary(items: managedDependencies.values.map({ ($0.name, $0) }))
        let dependencyMap = Dictionary(items: graph.packages.map({ package in
            (package, managedDependenciesByName[package.name])
        }))

        return (graph, dependencyMap)
    }

    /// Removes the clone and checkout of the provided specifier.
    func remove(specifier: RepositorySpecifier) throws {
        guard var dependency = managedDependencies[specifier] else {
            fatalError("This should never happen, trying to remove \(specifier) which isn't in workspace")
        }

        // Save the state.
        try managedDependencies.saveState()
    }
}

/// A result which can be loaded.
