// // PerforceLibrary.swift // DocHub // // Created by Tristan Juricek on 6/11/14. // Copyright (c) 2014 Perforce. All rights reserved. // import Foundation // The P4Library represents a single remote Perforce server. // // Each P4Library provides connections to model objects that depend upon it. @objc class P4Library : Library { var connectionSettings: P4ConnectionSettings var minConnections = 5 var freeConnections:P4ClientApi[] = [] var usedConnections:P4ClientApi[] = [] init(settings: P4ConnectionSettings) { connectionSettings = settings } deinit { for conn in freeConnections { conn.disconnect(nil) } for conn in usedConnections { conn.disconnect(nil) } } var name: String { return "\(connectionSettings.hostname)" } func createConnection() -> P4ClientApi { let clientApi = P4ClientApi() let host = connectionSettings.hostname let port = connectionSettings.port let portStr = "\(host):\(port)" let proto = ["tags": ""] clientApi.password = connectionSettings.token clientApi.user = connectionSettings.login clientApi.connectToPort(portStr, withProtocol: proto, error: nil) return clientApi } // The "areas" of a Perforce library are the depots. var areas: Area[] { return depots.map({$0 as Area}) } // TODO We should very likely cache this... not sure exactly for how long var depots: P4Depot[] { var err:NSError? = nil var depots:P4Depot[] = [] withConnection({ (err, depots) = $0.depots() }) return depots } func listDirs(parent:HasDepotPath) -> P4Dir[] { var path:String = "\(parent.depotPath)/*" var err:NSError? var dirs:Array? // Working around a bug in Swift beta withConnection({ let (err, vals) = $0.dirs(path) dirs = vals }) return dirs! } func listFiles(parent:HasDepotPath) -> P4File[] { var path:String = "\(parent.depotPath)/*" var err:NSError? var files:Array? // Working around a bug in Swift beta withConnection({ let (err, vals) = $0.files(path) files = vals }) return files! } func withConnection(fn:(P4ClientApi) -> ()) { let clientApi = acquireConnection() fn(clientApi) releaseConnection(clientApi) } func acquireConnection() -> P4ClientApi { var conn:P4ClientApi if (!freeConnections.isEmpty) { // we may want to validate the connection conn = freeConnections.removeLast() } else { conn = createConnection() } usedConnections.append(conn) return conn } func releaseConnection(api:P4ClientApi) -> () { if let removed = usedConnections.removeIf({ api === $0 }) { if (freeConnections.count <= minConnections) { freeConnections.append(removed) } else { removed.disconnect(nil) } } else { api.disconnect(nil) } } }