 
 	/// Attempts to load Cartfile or Cartfile.private from the given directory,
 	/// merging their dependencies.
-	public func loadCombinedCartfile() -> ColdSignal<Cartfile> {
+	public func loadCombinedCartfile() -> SignalProducer<Cartfile, CarthageError> {
 		let cartfileURL = directoryURL.URLByAppendingPathComponent(CarthageProjectCartfilePath, isDirectory: false)
 		let privateCartfileURL = directoryURL.URLByAppendingPathComponent(CarthageProjectPrivateCartfilePath, isDirectory: false)
 
-		let isNoSuchFileError = { (error: NSError) -> Bool in
-			return error.domain == NSCocoaErrorDomain && error.code == NSFileReadNoSuchFileError
-		}
-
-		let cartfile = ColdSignal.lazy {
-				.fromResult(Cartfile.fromFile(cartfileURL))
-			}
-			.catch { error -> ColdSignal<Cartfile> in
+		let isNoSuchFileError = { (error: CarthageError) -> Bool in
+			switch error {
+			case let .ReadFailed(_, underlyingError):
+				if let underlyingError = underlyingError {
+					return underlyingError.domain == NSCocoaErrorDomain && underlyingError.code == NSFileReadNoSuchFileError
+				} else {
+					return false
+				}
+
+			default:
+				return false
+			}
+		}
+
+		let cartfile = SignalProducer.try {
+				return Cartfile.fromFile(cartfileURL)
+			}
+			|> catch { error -> SignalProducer<Cartfile, CarthageError> in
 				if isNoSuchFileError(error) && NSFileManager.defaultManager().fileExistsAtPath(privateCartfileURL.path!) {
-					return .single(Cartfile())
-				}
-
-				return .error(error)
-			}
-
-		let privateCartfile = ColdSignal.lazy {
-				.fromResult(Cartfile.fromFile(privateCartfileURL))
-			}
-			.catch { error -> ColdSignal<Cartfile> in
+					return SignalProducer(value: Cartfile())
+				}
+
+				return SignalProducer(error: error)
+			}
+
+		let privateCartfile = SignalProducer.try {
+				return Cartfile.fromFile(privateCartfileURL)
+			}
+			|> catch { error -> SignalProducer<Cartfile, CarthageError> in
 				if isNoSuchFileError(error) {
-					return .single(Cartfile())
-				}
-
-				return .error(error)
-		}
-
-		return cartfile.zipWith(privateCartfile)
-			.tryMap { (var cartfile, privateCartfile) -> Result<Cartfile> in
+					return SignalProducer(value: Cartfile())
+				}
+
+				return SignalProducer(error: error)
+			}
+
+		return cartfile
+			|> zipWith(privateCartfile)
+			|> tryMap { (var cartfile, privateCartfile) -> Result<Cartfile, CarthageError> in
 				let duplicateDeps = cartfile.duplicateProjects().map { DuplicateDependency(project: $0, locations: ["\(CarthageProjectCartfilePath)"]) }
 					+ privateCartfile.duplicateProjects().map { DuplicateDependency(project: $0, locations: ["\(CarthageProjectPrivateCartfilePath)"]) }
 					+ duplicateProjectsInCartfiles(cartfile, privateCartfile).map { DuplicateDependency(project: $0, locations: ["\(CarthageProjectCartfilePath)", "\(CarthageProjectPrivateCartfilePath)"]) }

	///
	/// Sends the URL to each downloaded zip, after it has been moved to a
	/// less temporary location.
	private func downloadMatchingBinariesForProject(project: ProjectIdentifier, atRevision revision: String, fromRepository repository: GitHubRepository, withCredentials credentials: GitHubCredentials?) -> ColdSignal<NSURL> {
		return releaseForTag(revision, repository, credentials)
			.filter(binaryFrameworksCanBeProvidedByRelease)
			.on(next: { release in
				self._projectEventsSink.put(.DownloadingBinaries(project, release.nameWithFallback))
			})
			.concatMap { release in
				return ColdSignal
					.fromValues(release.assets)
					.filter(binaryFrameworksCanBeProvidedByAsset)
					.concatMap { asset in
						let fileURL = fileURLToCachedBinary(project, release, asset)

						return ColdSignal<NSURL>.lazy {
							if NSFileManager.defaultManager().fileExistsAtPath(fileURL.path!) {
								return .single(fileURL)
							} else {
								return downloadAsset(asset, credentials)
									.concatMap { downloadURL in cacheDownloadedBinary(downloadURL, toURL: fileURL) }
							}
						}
					}
			}

	///
	/// This will fetch dependency repositories as necessary, but will not check
	/// them out into the project's working directory.
	public func updatedResolvedCartfile() -> SignalProducer<ResolvedCartfile, CarthageError> {
		let resolver = Resolver(versionsForDependency: versionsForProject, cartfileForDependency: cartfileForDependency, resolvedGitReference: resolvedGitReference)

		return loadCombinedCartfile()
			|> joinMap(.Merge) { cartfile in resolver.resolveDependenciesInCartfile(cartfile) }
			|> reduce([]) { $0 + [ $1 ] }
			|> map { ResolvedCartfile(dependencies: $0) }
	}

	/// Updates the dependencies of the project to the latest version. The
	/// changes will be reflected in the working directory checkouts and
	/// Cartfile.resolved.
	public func updateDependencies() -> SignalProducer<(), CarthageError> {
		return updatedResolvedCartfile()
			|> tryMap { resolvedCartfile -> Result<(), CarthageError> in
				return self.writeResolvedCartfile(resolvedCartfile)
			}
			|> then(checkoutResolvedDependencies())
	}

	/// Installs binaries for the given project, if available.
	///
	/// Sends a boolean indicating whether binaries were installed.
	private func installBinariesForProject(project: ProjectIdentifier, atRevision revision: String) -> SignalProducer<Bool, CarthageError> {
		return SignalProducer.try {
				return success(self.useBinaries)
			}
			|> joinMap(.Merge) { useBinaries -> SignalProducer<Bool, CarthageError> in
				if useBinaries {
					return SignalProducer(value: false)
				}

				let checkoutDirectoryURL = self.directoryURL.URLByAppendingPathComponent(project.relativePath, isDirectory: true)

				switch project {
				case let .GitHub(repository):
					return self.downloadMatchingBinariesForProject(project, atRevision: revision, fromRepository: repository, withCredentials: nil)
						|> catch { error in
							switch error {
							case let .NetworkError(underlyingError):
								// If we were unable to fetch releases, try loading credentials from Git.
								if underlyingError.domain == NSURLErrorDomain {
									return GitHubCredentials.loadFromGit()
										|> joinMap(.Merge) { credentials in
											if let credentials = credentials {
												return self.downloadMatchingBinariesForProject(project, atRevision: revision, fromRepository: repository, withCredentials: credentials)
											} else {
												return SignalProducer(error: error)
											}
										}
								}

								fallthrough

							default:
								return SignalProducer(error: error)
							}
						}
						|> joinMap(.Concat, unzipArchiveToTemporaryDirectory)
						|> joinMap(.Concat) { directoryURL in
							return frameworksInDirectory(directoryURL)
								|> joinMap(.Merge, self.copyFrameworkToBuildFolder)
								|> on(completed: {
									_ = NSFileManager.defaultManager().trashItemAtURL(checkoutDirectoryURL, resultingItemURL: nil, error: nil)
								})
								|> then(SignalProducer(value: directoryURL))
						}
						|> tryMap { (temporaryDirectoryURL: NSURL) -> Result<Bool, CarthageError> in
							var error: NSError?
							if NSFileManager.defaultManager().removeItemAtURL(temporaryDirectoryURL, error: &error) {
								return success(true)
							} else {
								return failure(.WriteFailed(temporaryDirectoryURL, error))
							}
						}
						|> concat(SignalProducer(value: false))
						|> take(1)

				case .Git:
					return SignalProducer(value: false)
				}
			}
	}

	/// Downloads any binaries that may be able to be used instead of a
