Skip to content

Commit

Permalink
[Workspace] Move PinsStore to use SimplePersistence
Browse files Browse the repository at this point in the history
  • Loading branch information
ankitspd committed Mar 13, 2017
1 parent 053c793 commit 69c274d
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 43 deletions.
10 changes: 8 additions & 2 deletions Sources/Utility/SimplePersistence.swift
Expand Up @@ -36,14 +36,19 @@ public final class SimplePersistence {
/// The path at which we persist the state.
private let statePath: AbsolutePath

/// Writes the state files with pretty print JSON.
private let prettyPrint: Bool

public init(
fileSystem: FileSystem,
schemaVersion: Int,
statePath: AbsolutePath
statePath: AbsolutePath,
prettyPrint: Bool = false
) {
self.fileSystem = fileSystem
self.schemaVersion = schemaVersion
self.statePath = statePath
self.prettyPrint = prettyPrint
}

public func restoreState(_ object: SimplePersistanceProtocol) throws -> Bool {
Expand All @@ -69,6 +74,7 @@ public final class SimplePersistence {
"object": object
])
// FIXME: This should write atomically.
try fileSystem.writeFileContents(statePath, bytes: data.toBytes())
try fileSystem.writeFileContents(
statePath, bytes: data.toBytes(prettyPrint: self.prettyPrint))
}
}
57 changes: 21 additions & 36 deletions Sources/Workspace/PinsStore.swift
Expand Up @@ -9,7 +9,7 @@
*/

import Basic
import struct Utility.Version
import Utility
import SourceControl
import typealias PackageGraph.RepositoryPackageConstraint

Expand All @@ -18,7 +18,7 @@ public enum PinOperationError: Swift.Error {
case autoPinEnabled
}

public struct PinsStore {
public final class PinsStore {
public struct Pin {
/// The package name of the pinned dependency.
public let package: String
Expand Down Expand Up @@ -62,6 +62,8 @@ public struct PinsStore {
return AnySequence<Pin>(pinsMap.values)
}

fileprivate let persistence: SimplePersistence

/// Create a new pins store.
///
/// - Parameters:
Expand All @@ -70,13 +72,18 @@ public struct PinsStore {
public init(pinsFile: AbsolutePath, fileSystem: FileSystem) throws {
self.pinsFile = pinsFile
self.fileSystem = fileSystem
self.persistence = SimplePersistence(
fileSystem: fileSystem,
schemaVersion: 1,
statePath: pinsFile,
prettyPrint: true)
pinsMap = [:]
autoPin = true
try restoreState()
_ = try self.persistence.restoreState(self)
}

/// Update the autopin setting. Writes the setting to pins file.
public mutating func setAutoPin(on value: Bool) throws {
public func setAutoPin(on value: Bool) throws {
autoPin = value
try saveState()
}
Expand All @@ -90,7 +97,7 @@ public struct PinsStore {
/// - state: The state to pin at.
/// - reason: The reason for pinning.
/// - Throws: PinOperationError
public mutating func pin(
public func pin(
package: String,
repository: RepositorySpecifier,
state: CheckoutState,
Expand All @@ -113,7 +120,7 @@ public struct PinsStore {
/// - Returns: The pin which was removed.
/// - Throws: PinOperationError
@discardableResult
public mutating func unpin(package: String) throws -> Pin {
public func unpin(package: String) throws -> Pin {
// Ensure autopin is not on.
guard !autoPin else {
throw PinOperationError.autoPinEnabled
Expand All @@ -127,7 +134,7 @@ public struct PinsStore {
}

/// Unpin all of the currently pinnned dependencies.
public mutating func unpinAll() throws {
public func unpinAll() throws {
// Reset the pins map.
pinsMap = [:]
// Save the state.
Expand All @@ -144,45 +151,23 @@ public struct PinsStore {
}

/// Persistence.
extension PinsStore {
// FIXME: A lot of the persistence mechanism here is copied from
// `RepositoryManager`. It would be nice to get actual infrastructure around
// persistence to handle the boilerplate parts.

private enum PersistenceError: Swift.Error {
/// There was a missing or malformed key.
case unexpectedData
}
extension PinsStore: SimplePersistanceProtocol {

/// The current schema version for the persisted information.
private static let currentSchemaVersion = 1
fileprivate func saveState() throws {
try self.persistence.saveState(self)
}

fileprivate mutating func restoreState() throws {
if !fileSystem.exists(pinsFile) {
return
}
// Load the state.
let json = try JSON(bytes: try fileSystem.readFileContents(pinsFile))

// Load the state from JSON.
// FIXME: We will need migration support when we update pins schema.
guard try json.get("version") == PinsStore.currentSchemaVersion else {
fatalError("Migration not supported yet")
}
// Load the pins.
public func restore(from json: JSON) throws {
self.autoPin = try json.get("autoPin")
self.pinsMap = try Dictionary(items: json.get("pins").map{($0.package, $0)})
}

/// Saves the current state of pins.
fileprivate mutating func saveState() throws {
let data = JSON([
"version": PinsStore.currentSchemaVersion,
public func toJSON() -> JSON {
return JSON([
"pins": pins.sorted{$0.package < $1.package}.toJSON(),
"autoPin": autoPin,
])
// FIXME: This should write atomically.
try fileSystem.writeFileContents(pinsFile, bytes: data.toBytes(prettyPrint: true))
}
}

Expand Down
2 changes: 1 addition & 1 deletion Tests/CommandsTests/PackageToolTests.swift
Expand Up @@ -18,7 +18,7 @@ import SourceControl
import TestSupport
import Utility
import Workspace
@testable import struct Workspace.PinsStore
@testable import class Workspace.PinsStore

final class PackageToolTests: XCTestCase {
private func execute(_ args: [String], chdir: AbsolutePath? = nil) throws -> String {
Expand Down
8 changes: 4 additions & 4 deletions Tests/WorkspaceTests/PinsStoreTests.swift
Expand Up @@ -11,7 +11,7 @@
import XCTest

import Basic
import struct Utility.Version
import Utility
import TestSupport
import SourceControl
@testable import Workspace
Expand All @@ -34,7 +34,7 @@ final class PinsStoreTests: XCTestCase {

let fs = InMemoryFileSystem()
let pinsFile = AbsolutePath("/pinsfile.txt")
var store = try PinsStore(pinsFile: pinsFile, fileSystem: fs)
let store = try PinsStore(pinsFile: pinsFile, fileSystem: fs)
// Pins file should not be created right now.
XCTAssert(!fs.exists(pinsFile))
XCTAssert(store.pins.map{$0}.isEmpty)
Expand All @@ -45,13 +45,13 @@ final class PinsStoreTests: XCTestCase {

// Test autopin toggle and persistence.
do {
var store = try PinsStore(pinsFile: pinsFile, fileSystem: fs)
let store = try PinsStore(pinsFile: pinsFile, fileSystem: fs)
XCTAssert(store.autoPin)
try store.setAutoPin(on: false)
XCTAssertFalse(store.autoPin)
}
do {
var store = try PinsStore(pinsFile: pinsFile, fileSystem: fs)
let store = try PinsStore(pinsFile: pinsFile, fileSystem: fs)
XCTAssertFalse(store.autoPin)
try store.setAutoPin(on: true)
XCTAssert(store.autoPin)
Expand Down

0 comments on commit 69c274d

Please sign in to comment.