         }
     }
 
+    // FIXME: Temporary shim while we transition to the new methods.
+    public func loadDependencyManifests(
+        rootManifests: [Manifest],
+        diagnostics: DiagnosticsEngine
+    ) -> DependencyManifests {
+        return loadDependencyManifests(root: PackageGraphRoot(manifests: rootManifests), diagnostics: diagnostics)
+    }
+
+    /// Load the manifests for the current dependency tree.
+    ///
+    /// This will load the manifests for the root package as well as all the
+    /// current dependencies from the working checkouts.
+    public func loadDependencyManifests(
+        root: PackageGraphRoot,
+        diagnostics: DiagnosticsEngine
+    ) -> DependencyManifests {
+
+        // Try to load current managed dependencies, or emit and return.
+        do {
+            try fixManagedDependencies()
+        } catch {
+            diagnostics.emit(error)
+            return DependencyManifests(root: root, dependencies: [])
+        }
+
+        let rootDependencyManifests = root.dependencies.flatMap({
+            // FIXME: We need to emit any errors here to the diagnostics (SR-4262).
+            return loadManifest(forDependencyURL: $0.url)
+        })
+        let inputManifests = root.manifests + rootDependencyManifests
+
+        // Compute the transitive closure of available dependencies.
+        let dependencies = transitiveClosure(inputManifests.map({ KeyedPair($0, key: $0.url) })) { node in
+            return node.item.package.dependencies.flatMap({ dependency in
+                let manifest = loadManifest(forDependencyURL: dependency.url)
+                return manifest.flatMap({ KeyedPair($0, key: $0.url) })
+            })
+        }
+        // FIXME: Remove bang and emit errors (SR-4262).
+        let deps = (rootDependencyManifests + dependencies.map({ $0.item })).map({ ($0, managedDependencies[$0.url]!) })
+        return DependencyManifests(root: root, dependencies: deps)
+    }
+
+    /// 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)
+    }
+
+    /// Loads and returns manifests at the given paths.
+    public func loadRootManifests(
+        packages: [AbsolutePath],
+        diagnostics: DiagnosticsEngine
+    ) -> [Manifest] {
+
+        func load(_ package: AbsolutePath) throws -> Manifest {
+            let toolsVersion = try toolsVersionLoader.load(at: package, fileSystem: fileSystem)
+            guard currentToolsVersion >= toolsVersion else {
+                throw WorkspaceDiagnostics.IncompatibleToolsVersion(
+                    rootPackagePath: package,
+                    requiredToolsVersion: toolsVersion,
+                    currentToolsVersion: currentToolsVersion)
+            }
+            return try manifestLoader.load(
+                package: package, baseURL: package.asString, manifestVersion: toolsVersion.manifestVersion)
+        }
+
+        var manifests = [Manifest]()
+        for package in packages {
+            do {
+                try manifests.append(load(package))
+            } catch {
+                diagnostics.emit(error)
+            }
+        }
+        return manifests
+    }
+}
+
+// MARK: - Editing Functions
+
+extension Workspace {
+
+    /// Edit implementation.
+    func _edit(
+        dependency: ManagedDependency,
+        packageName: String,
+        diagnostics: DiagnosticsEngine,
+        path: AbsolutePath? = nil,
+        revision: Revision? = nil,
+        checkoutBranch: String? = nil
+    ) throws {
+        // Check if we can edit this dependency.
+        guard case .checkout(let checkoutState) = dependency.state else {
+            throw WorkspaceDiagnostics.DependencyAlreadyInEditMode(dependencyURL: dependency.repository.url)
+        }
+
+        // If a path is provided then we use it as destination. If not, we
+        // use the folder with packageName inside editablesPath.
+        let destination = path ?? editablesPath.appending(component: packageName)
+
+        // If there is something present at the destination, we confirm it has
+        // a valid manifest with name same as the package we are trying to edit.
+        if fileSystem.exists(destination) {
+            let manifest = try loadManifest(packagePath: destination, url: dependency.repository.url, version: nil)
+
+            guard manifest.name == packageName else {
+                throw WorkspaceDiagnostics.MismatchingDestinationPackage(
+                    editPath: destination,
+                    expectedPackage: packageName,
+                    destinationPackage: manifest.name)
+            }
+
+            // Emit warnings for branch and revision, if they're present.
+            if let checkoutBranch = checkoutBranch {
+                delegate.warning(message: "not checking out branch '\(checkoutBranch)' for dependency '\(packageName)'")
+            }
+            if let revision = revision {
+                delegate.warning(message: "not using revsion '\(revision.identifier)' for dependency '\(packageName)'")
+            }
+        } else {
+            // Otherwise, create a checkout at the destination from our repository store.
+            //
+            // Get handle to the repository.
+            let handle = try repositoryManager.lookupSynchronously(repository: dependency.repository)
+            let repo = try handle.open()
+
+            // Do preliminary checks on branch and revision, if provided.
+            if let branch = checkoutBranch, repo.exists(revision: Revision(identifier: branch)) {
+                throw WorkspaceDiagnostics.BranchAlreadyExists(
+                    dependencyURL: dependency.repository.url,
+                    branch: branch)
+            }
+            if let revision = revision, !repo.exists(revision: revision) {
+                throw WorkspaceDiagnostics.RevisionDoesNotExist(
+                    dependencyURL: dependency.repository.url,
+                    revision: revision.identifier)
+            }
+
+            try handle.cloneCheckout(to: destination, editable: true)
+            let workingRepo = try repositoryManager.provider.openCheckout(at: destination)
+            try workingRepo.checkout(revision: revision ?? checkoutState.revision)
+
+            // Checkout to the new branch if provided.
+            if let branch = checkoutBranch {
+                try workingRepo.checkout(newBranch: branch)
+            }
+        }
+
+        // For unmanaged dependencies, create the symlink under editables dir.
+        if let path = path {
+            try fileSystem.createDirectory(editablesPath)
+            // FIXME: We need this to work with InMem file system too.
+            try createSymlink(
+                editablesPath.appending(component: packageName),
+                pointingAt: path,
+                relative: false)
+        }
+
+        // Save the new state.
+        managedDependencies[dependency.repository] = dependency.editedDependency(
+            subpath: RelativePath(packageName), unmanagedPath: path)
+        try managedDependencies.saveState()
+    }
+}
+
+// MARK: - Pinning Functions
+
+extension Workspace {
+
+    /// Pins the managed dependency.
+    fileprivate func pin(
+        pinsStore: PinsStore,
+        dependency: ManagedDependency,
+        package: String,
+        reason: String?
+    ) throws {
+        let checkoutState: CheckoutState
+
+        switch dependency.state {
+        case .checkout(let state):
+            checkoutState = state
+        case .edited:
+            // For editable dependencies, pin the underlying dependency if we have them.
+            if let basedOn = dependency.basedOn, case .checkout(let state) = basedOn.state {
+                checkoutState = state
+            } else {
+                return delegate.warning(message: "not pinning \(package). It is being edited but is no longer needed.")
+            }
+        }
+        // Commit the pin.
+        try pinsStore.pin(
+            package: package,
+            repository: dependency.repository,
+            state: checkoutState,
+            reason: reason)
+    }
+
     /// Repin the packages.
     ///
     /// This methods pins all packages if auto pinning is on.
     /// Otherwise, only currently pinned packages are repinned.
-    private func repinPackages(_ pinsStore: PinsStore, dependencyManifests: DependencyManifests) throws {
+    fileprivate func repinPackages(_ pinsStore: PinsStore, dependencyManifests: DependencyManifests) throws {
         // If autopin is on, pin everything and return.
         if pinsStore.isAutoPinEnabled {
             return try pinAll(

            diagnostics.emit(error)
        }
    }
    
    /// Throwing version of edit
    private func _edit(
        dependency: ManagedDependency,
        packageName: String,
        diagnostics: DiagnosticsEngine,
        path: AbsolutePath? = nil,
        revision: Revision? = nil,
        checkoutBranch: String? = nil
    ) throws {
        // Check if we can edit this dependency.
        guard case .checkout(let checkoutState) = dependency.state else {
            throw WorkspaceDiagnostics.DependencyAlreadyInEditMode(dependencyURL: dependency.repository.url)
        }

        // If a path is provided then we use it as destination. If not, we
        // use the folder with packageName inside editablesPath.
        let destination = path ?? editablesPath.appending(component: packageName)

        // If there is something present at the destination, we confirm it has
        // a valid manifest with name same as the package we are trying to edit.
        if fileSystem.exists(destination) {
            let manifest = try loadManifest(packagePath: destination, url: dependency.repository.url, version: nil)
            
            guard manifest.name == packageName else {
                throw WorkspaceDiagnostics.MismatchingDestinationPackage(
                    editPath: destination,
                    expectedPackage: packageName,
                    destinationPackage: manifest.name)
            }

            // Emit warnings for branch and revision, if they're present.
            if let checkoutBranch = checkoutBranch {
                delegate.warning(message: "not checking out branch '\(checkoutBranch)' for dependency '\(packageName)'")
            }
            if let revision = revision {
                delegate.warning(message: "not using revsion '\(revision.identifier)' for dependency '\(packageName)'")
            }
        } else {
            // Otherwise, create a checkout at the destination from our repository store.
            //
            // Get handle to the repository.
            let handle = try repositoryManager.lookupSynchronously(repository: dependency.repository)
            let repo = try handle.open()

            // Do preliminary checks on branch and revision, if provided.
            if let branch = checkoutBranch, repo.exists(revision: Revision(identifier: branch)) {
                throw WorkspaceDiagnostics.BranchAlreadyExists(
                    dependencyURL: dependency.repository.url,
                    branch: branch)
            }
            if let revision = revision, !repo.exists(revision: revision) {
                throw WorkspaceDiagnostics.RevisionDoesNotExist(
                    dependencyURL: dependency.repository.url,
                    revision: revision.identifier)
            }

            try handle.cloneCheckout(to: destination, editable: true)
            let workingRepo = try repositoryManager.provider.openCheckout(at: destination)
            try workingRepo.checkout(revision: revision ?? checkoutState.revision)

            // Checkout to the new branch if provided.
            if let branch = checkoutBranch {
                try workingRepo.checkout(newBranch: branch)
            }
        }

        // For unmanaged dependencies, create the symlink under editables dir.
        if let path = path {
            try fileSystem.createDirectory(editablesPath)
            // FIXME: We need this to work with InMem file system too.
            try createSymlink(
                editablesPath.appending(component: packageName),
                pointingAt: path,
                relative: false)
        }

        // Save the new state.
        managedDependencies[dependency.repository] = dependency.editedDependency(
            subpath: RelativePath(packageName), unmanagedPath: path)
        try managedDependencies.saveState()
    }

    /// Ends the edit mode of a dependency which is in edit mode.
    ///

        }
    }

    /// Cleans the build artefacts from workspace data.
    ///
    /// - Parameters:
    ///     - diagnostics: The diagnostics engine that reports errors, warnings
    ///       and notes.
    public func clean(with diagnostics: DiagnosticsEngine) {

        // These are the things we don't want to remove while cleaning.
        let protectedAssets = Set<String>([
            repositoryManager.path,
            checkoutsPath,
            managedDependencies.statePath,
            ].map({ path in
                // Assert that these are present inside data directory.
                assert(path.parentDirectory == dataPath)
                return path.basename
            }))

        // If we have no data yet, we're done.
        guard fileSystem.exists(dataPath) else {
            return
        }

        guard let contents = diagnostics.wrap({ try fileSystem.getDirectoryContents(dataPath) }) else {
            return
        }

        // Remove all but protected paths.
        let contentsToRemove = Set(contents).subtracting(protectedAssets)
        for name in contentsToRemove {
            fileSystem.removeFileTree(dataPath.appending(RelativePath(name)))
        }
    }

    /// Resets the entire workspace by removing the data directory.
    ///
    /// - Parameters:
    ///     - diagnostics: The diagnostics engine that reports errors, warnings
    ///       and notes.
    public func reset(with diagnostics: DiagnosticsEngine) {
        let removed = diagnostics.wrap({
            // Make all checkouts mutable.
            try fileSystem.set(attribute: .mutable, path: checkoutsPath, recursive: true)

            // Reset manaked dependencies.
            try managedDependencies.reset()
        })

        guard removed else { return }

        repositoryManager.reset()
        fileSystem.removeFileTree(dataPath)
    }

    /// Updates the current dependencies.
