Permalink
Switch branches/tags
swift-DEVELOPMENT-SNAPSHOT-2018-07-20-a swift-DEVELOPMENT-SNAPSHOT-2018-07-19-a swift-DEVELOPMENT-SNAPSHOT-2018-07-18-a swift-DEVELOPMENT-SNAPSHOT-2018-07-17-a swift-DEVELOPMENT-SNAPSHOT-2018-07-16-a swift-DEVELOPMENT-SNAPSHOT-2018-07-14-a swift-DEVELOPMENT-SNAPSHOT-2018-07-13-a swift-DEVELOPMENT-SNAPSHOT-2018-07-12-a swift-DEVELOPMENT-SNAPSHOT-2018-07-11-a swift-DEVELOPMENT-SNAPSHOT-2018-07-09-a swift-DEVELOPMENT-SNAPSHOT-2018-07-07-a swift-DEVELOPMENT-SNAPSHOT-2018-07-06-a swift-DEVELOPMENT-SNAPSHOT-2018-07-05-a swift-DEVELOPMENT-SNAPSHOT-2018-07-04-a swift-DEVELOPMENT-SNAPSHOT-2018-07-03-a swift-DEVELOPMENT-SNAPSHOT-2018-07-02-a swift-DEVELOPMENT-SNAPSHOT-2018-07-01-a swift-DEVELOPMENT-SNAPSHOT-2018-06-30-a swift-DEVELOPMENT-SNAPSHOT-2018-06-29-a swift-DEVELOPMENT-SNAPSHOT-2018-06-27-a swift-DEVELOPMENT-SNAPSHOT-2018-06-26-a swift-DEVELOPMENT-SNAPSHOT-2018-06-25-a swift-DEVELOPMENT-SNAPSHOT-2018-06-24-a swift-DEVELOPMENT-SNAPSHOT-2018-06-23-a swift-DEVELOPMENT-SNAPSHOT-2018-06-22-a swift-DEVELOPMENT-SNAPSHOT-2018-06-21-a swift-DEVELOPMENT-SNAPSHOT-2018-06-20-a swift-DEVELOPMENT-SNAPSHOT-2018-06-19-a swift-DEVELOPMENT-SNAPSHOT-2018-06-18-a swift-DEVELOPMENT-SNAPSHOT-2018-06-17-a swift-DEVELOPMENT-SNAPSHOT-2018-06-16-a swift-DEVELOPMENT-SNAPSHOT-2018-06-15-a swift-DEVELOPMENT-SNAPSHOT-2018-06-14-a swift-DEVELOPMENT-SNAPSHOT-2018-06-08-a swift-DEVELOPMENT-SNAPSHOT-2018-06-07-a swift-DEVELOPMENT-SNAPSHOT-2018-06-06-a swift-DEVELOPMENT-SNAPSHOT-2018-06-05-a swift-DEVELOPMENT-SNAPSHOT-2018-06-04-a swift-DEVELOPMENT-SNAPSHOT-2018-06-03-a swift-DEVELOPMENT-SNAPSHOT-2018-06-02-a swift-DEVELOPMENT-SNAPSHOT-2018-06-01-a swift-DEVELOPMENT-SNAPSHOT-2018-05-31-a swift-DEVELOPMENT-SNAPSHOT-2018-05-30-a swift-DEVELOPMENT-SNAPSHOT-2018-05-29-a swift-DEVELOPMENT-SNAPSHOT-2018-05-28-a swift-DEVELOPMENT-SNAPSHOT-2018-05-27-a swift-DEVELOPMENT-SNAPSHOT-2018-05-26-a swift-DEVELOPMENT-SNAPSHOT-2018-05-25-a swift-DEVELOPMENT-SNAPSHOT-2018-05-24-a swift-DEVELOPMENT-SNAPSHOT-2018-05-23-a swift-DEVELOPMENT-SNAPSHOT-2018-05-22-a swift-DEVELOPMENT-SNAPSHOT-2018-05-21-a swift-DEVELOPMENT-SNAPSHOT-2018-05-20-a swift-DEVELOPMENT-SNAPSHOT-2018-05-19-a swift-DEVELOPMENT-SNAPSHOT-2018-05-18-a swift-DEVELOPMENT-SNAPSHOT-2018-05-17-a swift-DEVELOPMENT-SNAPSHOT-2018-05-14-a swift-DEVELOPMENT-SNAPSHOT-2018-05-13-a swift-DEVELOPMENT-SNAPSHOT-2018-05-11-a swift-DEVELOPMENT-SNAPSHOT-2018-05-10-a swift-DEVELOPMENT-SNAPSHOT-2018-05-08-a swift-DEVELOPMENT-SNAPSHOT-2018-04-25-a swift-DEVELOPMENT-SNAPSHOT-2018-04-24-a swift-DEVELOPMENT-SNAPSHOT-2018-04-23-a swift-DEVELOPMENT-SNAPSHOT-2018-04-22-a swift-DEVELOPMENT-SNAPSHOT-2018-04-21-a swift-DEVELOPMENT-SNAPSHOT-2018-04-20-a swift-DEVELOPMENT-SNAPSHOT-2018-04-19-a swift-DEVELOPMENT-SNAPSHOT-2018-04-18-a swift-DEVELOPMENT-SNAPSHOT-2018-04-17-a swift-DEVELOPMENT-SNAPSHOT-2018-04-16-a swift-DEVELOPMENT-SNAPSHOT-2018-04-15-a swift-DEVELOPMENT-SNAPSHOT-2018-04-13-a swift-DEVELOPMENT-SNAPSHOT-2018-04-12-a swift-DEVELOPMENT-SNAPSHOT-2018-04-11-a swift-DEVELOPMENT-SNAPSHOT-2018-04-10-a swift-DEVELOPMENT-SNAPSHOT-2018-04-09-a swift-DEVELOPMENT-SNAPSHOT-2018-04-08-a swift-DEVELOPMENT-SNAPSHOT-2018-04-07-a swift-DEVELOPMENT-SNAPSHOT-2018-04-06-a swift-DEVELOPMENT-SNAPSHOT-2018-04-05-a swift-DEVELOPMENT-SNAPSHOT-2018-04-04-a swift-DEVELOPMENT-SNAPSHOT-2018-04-03-a swift-DEVELOPMENT-SNAPSHOT-2018-04-02-a swift-DEVELOPMENT-SNAPSHOT-2018-04-01-a swift-DEVELOPMENT-SNAPSHOT-2018-03-31-a swift-DEVELOPMENT-SNAPSHOT-2018-03-30-a swift-DEVELOPMENT-SNAPSHOT-2018-03-28-a swift-DEVELOPMENT-SNAPSHOT-2018-03-26-a swift-DEVELOPMENT-SNAPSHOT-2018-03-25-a swift-DEVELOPMENT-SNAPSHOT-2018-03-17-a swift-DEVELOPMENT-SNAPSHOT-2018-03-15-a swift-DEVELOPMENT-SNAPSHOT-2018-03-14-a swift-DEVELOPMENT-SNAPSHOT-2018-03-13-a swift-DEVELOPMENT-SNAPSHOT-2018-03-11-a swift-DEVELOPMENT-SNAPSHOT-2018-03-08-a swift-DEVELOPMENT-SNAPSHOT-2018-03-07-a swift-DEVELOPMENT-SNAPSHOT-2018-03-06-a swift-DEVELOPMENT-SNAPSHOT-2018-03-05-a swift-DEVELOPMENT-SNAPSHOT-2018-03-04-a
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
279 lines (239 sloc) 8.43 KB
/*
This source file is part of the Swift.org open source project
Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See http://swift.org/LICENSE.txt for license information
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/
import Basic
import PackageGraph
import PackageModel
import SourceControl
import Utility
/// An individual managed dependency.
///
/// Each dependency will have a checkout containing the sources at a
/// particular revision, and may have an associated version.
public final class ManagedDependency: JSONMappable, JSONSerializable {
/// Represents the state of the managed dependency.
public enum State: Equatable {
/// The dependency is a managed checkout.
case checkout(CheckoutState)
/// The dependency is in edited state.
///
/// If the path is non-nil, the dependency is managed by a user and is
/// located at the path. In other words, this dependency is being used
/// for top of the tree style development.
case edited(AbsolutePath?)
// The dependency is a local package.
case local
/// Returns true if state is checkout.
var isCheckout: Bool {
if case .checkout = self { return true }
return false
}
}
/// The package reference.
public let packageRef: PackageReference
/// The state of the managed dependency.
public let state: State
/// The checked out path of the dependency on disk, relative to the workspace checkouts path.
public let subpath: RelativePath
/// A dependency which in editable state is based on a dependency from
/// which it edited from.
///
/// This information is useful so it can be restored when users
/// unedit a package.
var basedOn: ManagedDependency?
init(
packageRef: PackageReference,
subpath: RelativePath,
checkoutState: CheckoutState
) {
self.packageRef = packageRef
self.state = .checkout(checkoutState)
self.basedOn = nil
self.subpath = subpath
}
/// Create a dependency present locally on the filesystem.
static func local(
packageRef: PackageReference
) -> ManagedDependency {
return ManagedDependency(
packageRef: packageRef,
state: .local,
// FIXME: This is just a fake entry, we should fix it.
subpath: RelativePath(packageRef.identity),
basedOn: nil
)
}
private init(
packageRef: PackageReference,
state: State,
subpath: RelativePath,
basedOn: ManagedDependency?
) {
self.packageRef = packageRef
self.subpath = subpath
self.basedOn = basedOn
self.state = state
}
private init(
basedOn dependency: ManagedDependency,
subpath: RelativePath,
unmanagedPath: AbsolutePath?
) {
assert(dependency.state.isCheckout)
self.basedOn = dependency
self.packageRef = dependency.packageRef
self.subpath = subpath
self.state = .edited(unmanagedPath)
}
/// Create an editable managed dependency based on a dependency which
/// was *not* in edit state.
///
/// - Parameters:
/// - subpath: The subpath inside the editables directory.
/// - unmanagedPath: A custom absolute path instead of the subpath.
func editedDependency(subpath: RelativePath, unmanagedPath: AbsolutePath?) -> ManagedDependency {
return ManagedDependency(basedOn: self, subpath: subpath, unmanagedPath: unmanagedPath)
}
public init(json: JSON) throws {
self.packageRef = try json.get("packageRef")
self.subpath = try RelativePath(json.get("subpath"))
self.basedOn = json.get("basedOn")
self.state = try json.get("state")
}
public func toJSON() -> JSON {
return .init([
"packageRef": packageRef.toJSON(),
"subpath": subpath.asString,
"basedOn": basedOn.toJSON(),
"state": state,
])
}
}
extension ManagedDependency.State: JSONMappable, JSONSerializable {
public func toJSON() -> JSON {
switch self {
case .checkout(let checkoutState):
return .init([
"name": "checkout",
"checkoutState": checkoutState,
])
case .edited(let path):
return .init([
"name": "edited",
"path": path.toJSON(),
])
case .local:
return .init([
"name": "local",
])
}
}
public init(json: JSON) throws {
let name: String = try json.get("name")
switch name {
case "checkout":
self = try .checkout(json.get("checkoutState"))
case "edited":
let path: String? = json.get("path")
self = .edited(path.map({AbsolutePath($0)}))
case "local":
self = .local
default:
throw JSON.MapError.custom(key: nil, message: "Invalid state \(name)")
}
}
}
/// Represents a collection of managed dependency which are persisted on disk.
public final class ManagedDependencies: SimplePersistanceProtocol {
enum Error: Swift.Error, CustomStringConvertible {
case dependencyNotFound(name: String)
var description: String {
switch self {
case .dependencyNotFound(let name):
return "Could not find dependency '\(name)'"
}
}
}
/// The schema version of the resolved file.
///
/// * 2: Package identity.
/// * 1: Initial version.
static let schemaVersion: Int = 2
/// The current state of managed dependencies.
///
/// Key -> package identity.
private var dependencyMap: [String: ManagedDependency]
/// Path to the state file.
let statePath: AbsolutePath
/// persistence helper
let persistence: SimplePersistence
init(dataPath: AbsolutePath, fileSystem: FileSystem) {
let statePath = dataPath.appending(component: "dependencies-state.json")
self.dependencyMap = [:]
self.statePath = statePath
self.persistence = SimplePersistence(
fileSystem: fileSystem,
schemaVersion: ManagedDependencies.schemaVersion,
statePath: statePath)
// Load the state from disk, if possible.
//
// If the disk operation here fails, we ignore the error here.
// This means if managed dependencies data is corrupted or out of date,
// clients will not see the old data and managed dependencies will be
// reset. However there could be other errors, like permission issues,
// these errors will also be ignored but will surface when clients try
// to save the state.
do {
try self.persistence.restoreState(self)
} catch {
// FIXME: We should emit a warning here using the diagnostic engine.
print("\(error)")
}
}
public subscript(forIdentity identity: String) -> ManagedDependency? {
get {
assert(identity == identity.lowercased())
return dependencyMap[identity]
}
set {
assert(identity == identity.lowercased())
dependencyMap[identity] = newValue
}
}
/// Returns the dependency given a name or identity.
func dependency(forNameOrIdentity nameOrIdentity: String) throws -> ManagedDependency {
if let dependency = self[forIdentity: nameOrIdentity.lowercased()] {
return dependency
}
for value in values {
if value.packageRef.name == nameOrIdentity {
return value
}
}
throw Error.dependencyNotFound(name: nameOrIdentity)
}
func reset() throws {
dependencyMap = [:]
try saveState()
}
func saveState() throws {
try self.persistence.saveState(self)
}
public var values: AnySequence<ManagedDependency> {
return AnySequence<ManagedDependency>(dependencyMap.values)
}
public func restore(from json: JSON) throws {
self.dependencyMap = try Dictionary(items:
json.get("dependencies").map({ ($0.packageRef.identity, $0) })
)
}
public func toJSON() -> JSON {
return JSON([
"dependencies": values.toJSON(),
])
}
}