Skip to content

Commit

Permalink
Merge branch 'master' into 0.4-development
Browse files Browse the repository at this point in the history
Conflicts:
	CarthageKit/Resolver.swift
	CarthageKit/Version.swift
	CarthageKitTests/VersionSpec.swift
	Documentation/Artifacts.md
  • Loading branch information
jspahrsummers committed Dec 9, 2014
2 parents ca37abc + 0474b34 commit ffd40bf
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 10 deletions.
43 changes: 34 additions & 9 deletions CarthageKit/Errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,24 @@ import Foundation
/// The domain for all errors originating within Carthage.
public let CarthageErrorDomain: NSString = "org.carthage.Carthage"

/// Possible error codes within `CarthageErrorDomain`.
/// Possible error codes with `CarthageErrorDomain`.
public enum CarthageErrorCode: Int {
case InvalidArgument
case MissingBuildSetting
case IncompatibleRequirements
case TaggedVersionNotFound
case RequiredVersionNotFound
case RepositoryCheckoutFailed
case ReadFailed
case WriteFailed
case ParseError

func error(userInfo: [NSObject: AnyObject]?) -> NSError {
return NSError(domain: CarthageErrorDomain, code: self.rawValue, userInfo: userInfo)
}
}

/// Possible errors within `CarthageErrorDomain`.
public enum CarthageError {
/// One or more arguments was invalid.
case InvalidArgument(description: String)
Expand All @@ -21,6 +38,9 @@ public enum CarthageError {

/// Incompatible version specifiers were given for a dependency.
case IncompatibleRequirements(ProjectIdentifier, VersionSpecifier, VersionSpecifier)

/// No tagged versions could be found for the dependency.
case TaggedVersionNotFound(ProjectIdentifier)

/// No existent version could be found to satisfy the version specifier for
/// a dependency.
Expand All @@ -42,42 +62,47 @@ public enum CarthageError {
public var error: NSError {
switch (self) {
case let .InvalidArgument(description):
return NSError(domain: CarthageErrorDomain, code: 2, userInfo: [
return CarthageErrorCode.InvalidArgument.error([
NSLocalizedDescriptionKey: description
])

case let .MissingBuildSetting(setting):
return NSError(domain: CarthageErrorDomain, code: 3, userInfo: [
return CarthageErrorCode.MissingBuildSetting.error([
NSLocalizedDescriptionKey: "xcodebuild did not return a value for build setting \(setting)"
])

case let .ReadFailed(fileURL):
return NSError(domain: CarthageErrorDomain, code: 4, userInfo: [
return CarthageErrorCode.ReadFailed.error([
NSLocalizedDescriptionKey: "Failed to read file or folder at \(fileURL.path!)"
])

case let .IncompatibleRequirements(dependency, first, second):
return NSError(domain: CarthageErrorDomain, code: 5, userInfo: [
return CarthageErrorCode.IncompatibleRequirements.error([
NSLocalizedDescriptionKey: "Could not pick a version for \(dependency), due to mutually incompatible requirements:\n\t\(first)\n\t\(second)"
])

case let .TaggedVersionNotFound(dependency):
return CarthageErrorCode.TaggedVersionNotFound.error([
NSLocalizedDescriptionKey: "No tagged versions found for \(dependency)"
])

case let .RequiredVersionNotFound(dependency, specifier):
return NSError(domain: CarthageErrorDomain, code: 6, userInfo: [
return CarthageErrorCode.RequiredVersionNotFound.error([
NSLocalizedDescriptionKey: "No available version for \(dependency) satisfies the requirement: \(specifier)"
])

case let .RepositoryCheckoutFailed(workingDirectoryURL, reason):
return NSError(domain: CarthageErrorDomain, code: 7, userInfo: [
return CarthageErrorCode.RepositoryCheckoutFailed.error([
NSLocalizedDescriptionKey: "Failed to check out repository into \(workingDirectoryURL.path!): \(reason)"
])

case let .WriteFailed(fileURL):
return NSError(domain: CarthageErrorDomain, code: 8, userInfo: [
return CarthageErrorCode.WriteFailed.error([
NSLocalizedDescriptionKey: "Failed to create \(fileURL.path!)"
])

case let .ParseError(description):
return NSError(domain: CarthageErrorDomain, code: 9, userInfo: [
return CarthageErrorCode.ParseError.error([
NSLocalizedDescriptionKey: "Parse error: \(description)"
])
}
Expand Down
9 changes: 9 additions & 0 deletions CarthageKit/Resolver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,15 @@ public struct Resolver {

default:
return self.versionsForDependency(dependency.project)
.reduce(initial: []) { $0 + [ $1 ] }
.map { nodes -> ColdSignal<PinnedVersion> in
if nodes.isEmpty {
return .error(CarthageError.TaggedVersionNotFound(dependency.project).error)
} else {
return .fromValues(nodes)
}
}
.merge(identity)
.filter { dependency.version.satisfiedBy($0) }
}
}()
Expand Down
24 changes: 23 additions & 1 deletion CarthageKit/Version.swift
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,18 @@ public enum VersionSpecifier: Equatable {
return withSemanticVersion { $0 >= requirement }

case let .CompatibleWith(requirement):
return withSemanticVersion { $0.major == requirement.major && $0 >= requirement }
return withSemanticVersion { version in
// According to SemVer, any 0.x.y release may completely break the
// exported API, so it's not safe to consider them compatible with one
// another. Only patch versions are compatible under 0.x, meaning 0.1.1 is
// compatible with 0.1.2, but not 0.2. This isn't according to the SemVer
// spec but keeps ~> useful for 0.x.y versions.
if version.major == 0 {
return version.minor == requirement.minor && version >= requirement
}

return version.major == requirement.major && version >= requirement
}
}
}
}
Expand Down Expand Up @@ -338,6 +349,17 @@ public func intersection(lhs: VersionSpecifier, rhs: VersionSpecifier) -> Versio
return nil
}

// According to SemVer, any 0.x.y release may completely break the
// exported API, so it's not safe to consider them compatible with one
// another. Only patch versions are compatible under 0.x, meaning 0.1.1 is
// compatible with 0.1.2, but not 0.2. This isn't according to the SemVer
// spec but keeps ~> useful for 0.x.y versions.
if lv.major == 0 && rv.major == 0 {
if lv.minor != rv.minor {
return nil
}
}

return .CompatibleWith(max(lv, rv))

case let (.CompatibleWith(lv), .Exactly(rv)):
Expand Down
14 changes: 14 additions & 0 deletions CarthageKitTests/VersionSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ class SemanticVersionSpec: QuickSpec {

class VersionSpecifierSpec: QuickSpec {
override func spec() {
let versionZeroOne = SemanticVersion.fromPinnedVersion(PinnedVersion("0.1.0")).value()!
let versionZeroOneOne = SemanticVersion.fromPinnedVersion(PinnedVersion("0.1.1")).value()!
let versionZeroTwo = SemanticVersion.fromPinnedVersion(PinnedVersion("0.2.0")).value()!
let versionOne = SemanticVersion.fromPinnedVersion(PinnedVersion("1.3.2")).value()!
let versionTwoZero = SemanticVersion.fromPinnedVersion(PinnedVersion("2.0.2")).value()!
let versionTwoOne = SemanticVersion.fromPinnedVersion(PinnedVersion("2.1.1")).value()!
Expand Down Expand Up @@ -92,6 +95,12 @@ class VersionSpecifierSpec: QuickSpec {
expect(specifier.satisfiedBy(versionTwoTwo.pinnedVersion!)).to(beTruthy())
expect(specifier.satisfiedBy(versionThree.pinnedVersion!)).to(beFalsy())
}

it("should allow only greater patch versions to satisfy 0.x") {
let specifier = VersionSpecifier.CompatibleWith(versionZeroOne)
expect(specifier.satisfiedBy(versionZeroOneOne.pinnedVersion!)).to(beTruthy())
expect(specifier.satisfiedBy(versionZeroTwo.pinnedVersion!)).to(beFalsy())
}
}

describe("intersection") {
Expand Down Expand Up @@ -124,6 +133,11 @@ class VersionSpecifierSpec: QuickSpec {
testIntersection(VersionSpecifier.Exactly(versionOne), VersionSpecifier.Exactly(versionOne), expected: VersionSpecifier.Exactly(versionOne))
testIntersection(VersionSpecifier.Exactly(versionTwoOne), VersionSpecifier.Exactly(versionOne), expected: nil)
}

it("should not let ~> 0.1.1 be compatible with 0.1.2, but not 0.2") {
testIntersection(VersionSpecifier.CompatibleWith(versionZeroOne), VersionSpecifier.CompatibleWith(versionZeroOneOne), expected: VersionSpecifier.CompatibleWith(versionZeroOneOne))
testIntersection(VersionSpecifier.CompatibleWith(versionZeroOne), VersionSpecifier.CompatibleWith(versionZeroTwo), expected: nil)
}
}
}
}
2 changes: 2 additions & 0 deletions Documentation/Artifacts.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ If no version requirement is given, any version of the dependency is allowed.

Compatibility is determined according to [Semantic Versioning](http://semver.org/). This means that any version greater than or equal to 1.5.1, but less than 2.0, will be considered “compatible” with 1.5.1.

According to SemVer, any 0.x.y release may completely break the exported API, so it's not safe to consider them compatible with one another. Only patch versions are compatible under 0.x, meaning 0.1.1 is compatible with 0.1.2, but not 0.2. This isn't according to the SemVer spec but keeps `~>` useful for 0.x.y versions.

**In all cases, Carthage will pin to a tag or SHA**, and only bump the tag or SHA when `carthage update` is run again in the future. This means that following a branch (for example) still results in commits that can be independently checked out just as they were originally.

#### Example Cartfile
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ The basic [workflow](#adding-frameworks-to-an-application) looks something like

Carthage builds your dependencies and provides you with binary frameworks, but you retain full control over your project structure and setup. Carthage does not automatically modify your project files or your build settings.

:warning: Frameworks built using Carthage will currently be rejected in iOS App Store submissions. This is a [known issue](https://github.com/Carthage/Carthage/issues/188) that should be fixed in the next release.

## Differences between Carthage and CocoaPods

[CocoaPods](http://cocoapods.org/) is a long-standing dependency manager for Cocoa. So why was Carthage created?
Expand Down

0 comments on commit ffd40bf

Please sign in to comment.