diff --git a/.gitignore b/.gitignore index 0dccff9..40713a5 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,5 @@ Carthage/Build .build dist SourceKittenDaemon.pkg -Packages \ No newline at end of file +Packages +Package.pins \ No newline at end of file diff --git a/Makefile b/Makefile index 0610c25..58fe43f 100644 --- a/Makefile +++ b/Makefile @@ -18,12 +18,10 @@ clean: rm -rf "$(BUILD)" .PHONY: install -install: $(DIST)$(BINARIES_FOLDER)/sourcekittendaemon $(DIST)$(LIB_FOLDER)/libCYaml.dylib $(DIST)$(LIB_FOLDER)/libCLibreSSL.dylib +install: $(DIST)$(BINARIES_FOLDER)/sourcekittendaemon mkdir -p "$(PREFIX)$(BINARIES_FOLDER)" mkdir -p "$(PREFIX)$(LIB_FOLDER)" cp -f "$(DIST)$(BINARIES_FOLDER)/sourcekittendaemon" "$(PREFIX)$(BINARIES_FOLDER)/" - cp -f "$(DIST)$(LIB_FOLDER)/libCYaml.dylib" "$(PREFIX)$(LIB_FOLDER)/" - cp -f "$(DIST)$(LIB_FOLDER)/libCLibreSSL.dylib" "$(PREFIX)$(LIB_FOLDER)/" .PHONY: test test: @@ -32,7 +30,7 @@ test: FIXTURE_PROJECT_FILE_PATH="$(ROOT_DIR)/Tests/SourceKittenDaemonTests/Fixtures/Project/Fixture.xcodeproj" \ swift test -SourceKittenDaemon.pkg: $(DIST)$(BINARIES_FOLDER)/sourcekittendaemon $(DIST)$(LIB_FOLDER)/libCYaml.dylib $(DIST)$(LIB_FOLDER)/libCLibreSSL.dylib +SourceKittenDaemon.pkg: $(DIST)$(BINARIES_FOLDER)/sourcekittendaemon pkgbuild \ --identifier "$(IDENTIFIER)" \ --root "$(DIST)" \ @@ -43,16 +41,11 @@ SourceKittenDaemon.pkg: $(DIST)$(BINARIES_FOLDER)/sourcekittendaemon $(DIST)$(LI $(DIST)$(BINARIES_FOLDER)/sourcekittendaemon: $(BUILD)/release/sourcekittend mkdir -p $(@D) cp $< $@ - install_name_tool -change $(PWD)/$(BUILD)/release/libCYaml.dylib $(PREFIX)$(LIB_FOLDER)/libCYaml.dylib $@ - install_name_tool -change $(PWD)/$(BUILD)/release/libCLibreSSL.dylib $(PREFIX)$(LIB_FOLDER)/libCLibreSSL.dylib $@ $(DIST)$(LIB_FOLDER)/%.dylib: $(BUILD)/release/%.dylib mkdir -p $(@D) cp $< $@ -$(BUILD)/release/libCYaml.dylib: $(BUILD)/release/sourcekittend -$(BUILD)/release/libCLibreSSL.dylib: $(BUILD)/release/sourcekittend - $(BUILD)/release/sourcekittend: $(SRC_FILES) mkdir -p $(@D) swift build -c release --build-path $(BUILD) diff --git a/Package.pins b/Package.pins new file mode 100644 index 0000000..e6c5edb --- /dev/null +++ b/Package.pins @@ -0,0 +1,72 @@ +{ + "autoPin": true, + "pins": [ + { + "package": "Clang_C", + "reason": null, + "repositoryURL": "https://github.com/norio-nomura/Clang_C.git", + "version": "1.0.2" + }, + { + "package": "Commandant", + "reason": null, + "repositoryURL": "https://github.com/Carthage/Commandant.git", + "version": "0.12.0" + }, + { + "package": "Embassy", + "reason": null, + "repositoryURL": "https://github.com/envoy/Embassy.git", + "version": "3.1.0" + }, + { + "package": "FileSystemWatcher", + "reason": null, + "repositoryURL": "https://github.com/felix91gr/FileSystemWatcher.git", + "version": "1.1.2" + }, + { + "package": "inotify", + "reason": null, + "repositoryURL": "https://github.com/felix91gr/inotify.git", + "version": "1.0.2" + }, + { + "package": "Result", + "reason": null, + "repositoryURL": "https://github.com/antitypical/Result.git", + "version": "3.2.2" + }, + { + "package": "SourceKit", + "reason": null, + "repositoryURL": "https://github.com/norio-nomura/SourceKit.git", + "version": "1.0.1" + }, + { + "package": "SourceKitten", + "reason": null, + "repositoryURL": "https://github.com/jpsim/SourceKitten.git", + "version": "0.17.5" + }, + { + "package": "SWXMLHash", + "reason": null, + "repositoryURL": "https://github.com/drmohundro/SWXMLHash.git", + "version": "3.1.0" + }, + { + "package": "XcodeEdit", + "reason": null, + "repositoryURL": "https://github.com/felix91gr/XcodeEdit.git", + "version": "1.1.2" + }, + { + "package": "Yams", + "reason": null, + "repositoryURL": "https://github.com/jpsim/Yams.git", + "version": "0.3.2" + } + ], + "version": 1 +} \ No newline at end of file diff --git a/Package.swift b/Package.swift index 557d13d..d947603 100644 --- a/Package.swift +++ b/Package.swift @@ -1,6 +1,6 @@ import PackageDescription -let package = Package( +var package = Package( name: "SourceKittenDaemon", targets: [ @@ -10,12 +10,17 @@ let package = Package( dependencies: [ .Package(url: "https://github.com/Carthage/Commandant.git", versions: Version(0, 12, 0).. Void), sendBody: ((Data) -> Void)) { + do { + let returnResult = try routeRequest(environ: environ) + startResponse("200 OK", []) + sendBody(Data(returnResult.utf8)) + sendBody(Data()) + } catch Abort.custom(status: let status, message: let message) { + startResponse("\(status) BAD REQUEST", []) + sendBody(Data(message.utf8)) + sendBody(Data()) + } catch let error { + startResponse("500 INTERNAL SERVER ERROR", []) + sendBody(Data("\(error)".utf8)) + sendBody(Data()) } - - droplet.get("/complete") { request in - guard let offsetString = request.headers["X-Offset"], - let offset = Int(offsetString) else { + } + + private func routeRequest(environ: [String: Any]) throws -> String { + let routes = [ + "/ping": servePing, + "/project": serveProject, + "/files": serveFiles, + "/complete": serveComplete, + ] + + guard let path = environ["PATH_INFO"] as? String, + let route = routes[path] else { throw Abort.custom( - status: .badRequest, - message: "{\"error\": \"Need X-Offset as completion offset for completion\"}" + status: 400, + message: "{\"error\": \"Could not generate file list\"}" ) - } + } + + return try route(environ) + } +} - guard let path = request.headers["X-Path"] else { +/** + Concrete implementation of the calls + */ +extension CompletionServer { + func servePing(environ: [String: Any]) throws -> String { + return "OK" + } + + func serveProject(environ: [String: Any]) throws -> String { + return self.completer.project.projectFile.path + } + + func serveFiles(environ: [String: Any]) throws -> String { + let files = self.completer.sourceFiles() + guard let jsonFiles = try? JSONSerialization.data( + withJSONObject: files, + options: JSONSerialization.WritingOptions.prettyPrinted + ), + let filesString = String(data: jsonFiles, encoding: String.Encoding.utf8) else { throw Abort.custom( - status: .badRequest, - message: "{\"error\": \"Need X-Path as path to the temporary buffer\"}" + status: 400, + message: "{\"error\": \"Could not generate file list\"}" ) - } - - print("[HTTP] GET /complete X-Offset:\(offset) X-Path:\(path)") - - let url = URL(fileURLWithPath: path) - let result = self.completer.complete(url, offset: offset) - - switch result { - case .success(result: _): - return result.asJSONString()! - case .failure(message: let msg): + } + return filesString + } + + func serveComplete(environ: [String: Any]) throws -> String { + guard let offsetString = environ["HTTP_X_OFFSET"] as? String, + let offset = Int(offsetString) else { throw Abort.custom( - status: .badRequest, - message: "{\"error\": \"\(msg)\"}" + status: 400, + message: "{\"error\": \"Need X-Offset as completion offset for completion\"}" ) - } + } + + guard let path = environ["HTTP_X_PATH"] as? String else { + throw Abort.custom( + status: 400, + message: "{\"error\": \"Need X-Path as path to the temporary buffer\"}" + ) + } + + print("[HTTP] GET /complete X-Offset:\(offset) X-Path:\(path)") + + let url = URL(fileURLWithPath: path) + let result = self.completer.complete(url, offset: offset) + + switch result { + case .success(result: _): + return result.asJSONString()! + case .failure(message: let msg): + throw Abort.custom( + status: 400, + message: "{\"error\": \"\(msg)\"}" + ) } } - - public func start() { - droplet.run(servers: ["default": (host: "0.0.0.0", port: port, securityLayer: .none)]) - } - } diff --git a/Sources/sourcekittend/StartCommand.swift b/Sources/sourcekittend/StartCommand.swift index eb7c301..fd0af21 100644 --- a/Sources/sourcekittend/StartCommand.swift +++ b/Sources/sourcekittend/StartCommand.swift @@ -34,9 +34,13 @@ struct StartCommand: CommandProtocol { target: options.target.isEmpty ? nil : options.target, configuration: options.configuration) - let server = CompletionServer(project: project, port: options.port) - server.start() - return .success() + do { + let server = try CompletionServer(project: project, port: options.port) + try server.start() + return .success() + } catch let error { + return Result.failure(CommandError.other(error)) + } } catch (let e as ProjectError) { return .failure(.project(e)) } catch (_) { @@ -94,12 +98,14 @@ enum CommandError: Error, CustomStringConvertible { case invalidArgument(description: String) case project(ProjectError) case unknown + case other(Error) /// An error message corresponding to this error. var description: String { switch self { case .invalidArgument(let description): return description case .project(let e): return e.description + case .other(let e): return "\(e)" default: return "An unknown error occured" } } diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift new file mode 100644 index 0000000..0e4db26 --- /dev/null +++ b/Tests/LinuxMain.swift @@ -0,0 +1,7 @@ +import XCTest +@testable import SourceKittenDaemonTests + +XCTMain([ + testCase(CompleterTests.allTests), + testCase(ProjectTests.allTests), +]) diff --git a/Tests/SourceKittenDaemonTests/CompleterTests.swift b/Tests/SourceKittenDaemonTests/CompleterTests.swift index 1937305..d295b57 100644 --- a/Tests/SourceKittenDaemonTests/CompleterTests.swift +++ b/Tests/SourceKittenDaemonTests/CompleterTests.swift @@ -8,9 +8,47 @@ class CompleterTests : XCTestCase { var project: Project! var completer: Completer! +#if os(Linux) + let doDebug = true +#else + let doDebug = false +#endif + + func debugMsg(_ msg : String) { + if(doDebug) { + print ("[DEBUG] " + msg) + } + } + override func setUp() { + debugMsg("Checking setUp func in CompleterTests") + + debugMsg("Starting super.setUp...") + super.setUp() + + debugMsg("Finished!. Creating a test var of type xcodeprojFixturePath...") + // debugMsg("Printing ProcessInfo.processInfo.environment") + // for (zeKey, zeValue) in ProcessInfo.processInfo.environment { + // debugMsg(zeKey + " : " + zeValue) + // } + + var _ = xcodeprojFixturePath() + + debugMsg("Worked!. Creating ProjectType from xcodeprojFixturePath...") + type = ProjectType.project(project: xcodeprojFixturePath()) + + debugMsg("[EXTRA] Printing ProjectType") + print(type) + debugMsg("[EXTRA] Success!") + + debugMsg("ProjectType is in order. Poking project var...") + debugMsg("The error seems to be in the following line.") + debugMsg("It will fail on the 'public convenience init(propertyListData data: Data)' method,") + debugMsg("On XCProjectFile.swift") + + project = try! Project(type: type, configuration: "Debug") completer = Completer(project: project) } @@ -54,7 +92,7 @@ class CompleterTests : XCTestCase { offset: 69) if let s = result.asJSONString() { - XCTAssertTrue(s =~ "sourcetext.*devices.withMediaType:") + XCTAssertTrue(s =~ "sourcetext.*devices") } } @@ -69,3 +107,19 @@ class CompleterTests : XCTestCase { } } + +#if os(Linux) + +extension CompleterTests { + static var allTests: [(String, (CompleterTests) -> () throws -> Void)] { + return [ + ("testCompletingAConstructor", testCompletingAConstructor), + ("testCompletingEnumConstructor", testCompletingEnumConstructor), + ("testCompletingAMethod", testCompletingAMethod), + ("testCompletingAMethodFromFramework", testCompletingAMethodFromFramework), + ("testCompletingAnImportStatement", testCompletingAnImportStatement), + ] + } +} + +#endif diff --git a/Tests/SourceKittenDaemonTests/ProjectTests.swift b/Tests/SourceKittenDaemonTests/ProjectTests.swift index 3e8b6cc..195cce1 100644 --- a/Tests/SourceKittenDaemonTests/ProjectTests.swift +++ b/Tests/SourceKittenDaemonTests/ProjectTests.swift @@ -69,3 +69,23 @@ class ProjectTests : XCTestCase { } } + +#if os(Linux) + +extension ProjectTests { + static var allTests: [(String, (ProjectTests) -> () throws -> Void)] { + return [ + ("testProjectDirIsCorrect", testProjectDirIsCorrect), + ("testReturnsTheCorrectSourceCodeObjects", testReturnsTheCorrectSourceCodeObjects), + ("testItCanOverrideTheSchemesTarget", testItCanOverrideTheSchemesTarget), + ("testItCanOverrideTheSchemesConfiguration", testItCanOverrideTheSchemesConfiguration), + ("testReturnsTheCorrectModuleName", testReturnsTheCorrectModuleName), + ("testReturnsTheCorrectSDKRoot", testReturnsTheCorrectSDKRoot), + ("testReturnsAListOfFrameworkSearchPaths", testReturnsAListOfFrameworkSearchPaths), + ("testReturnsCustomSwiftCompilerFlags", testReturnsCustomSwiftCompilerFlags), + ("testReturnsGccPreprocessorDefinitions", testReturnsGccPreprocessorDefinitions), + ] + } +} + +#endif