this repo has no description
at fixPythonPipStalling 152 lines 5.8 kB view raw
1#!/usr/bin/env swift 2/* 3This file is part of Darling. 4 5Copyright (C) 2017 Lubos Dolezel 6 7Darling is free software: you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation, either version 3 of the License, or 10(at your option) any later version. 11 12Darling is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along with Darling. If not, see <http://www.gnu.org/licenses/>. 19*/ 20 21import Foundation 22 23guard CommandLine.arguments.count == 3 else { 24 fatalError("Usage: \(CommandLine.arguments[0]) <Objective-C binary> <output directory>") 25} 26 27let copyright = "/*\n" + 28 "This file is part of Darling.\n" + 29 "\n" + 30 31 "Copyright (C) 2018 Lubos Dolezel\n" + 32 "\n" + 33 34 "Darling is free software: you can redistribute it and/or modify\n" + 35 "it under the terms of the GNU General Public License as published by\n" + 36 "the Free Software Foundation, either version 3 of the License, or\n" + 37 "(at your option) any later version.\n" + 38 "\n" + 39 40 "Darling is distributed in the hope that it will be useful,\n" + 41 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + 42 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + 43 "GNU General Public License for more details.\n" + 44 "\n" + 45 46 "You should have received a copy of the GNU General Public License\n" + 47 "along with Darling. If not, see <http://www.gnu.org/licenses/>.\n" + 48 "*/\n\n" 49 50let name = CommandLine.arguments[1] 51let outputDirectory = CommandLine.arguments[2] 52 53// So we can generate a "master header" 54var moduleName = (name as NSString).pathComponents.last! as String 55 56// Set up the environment for class-dump 57let pipe = Pipe() 58 59let classDump = Process() 60classDump.launchPath = "/bin/bash" 61classDump.arguments = ["-c","class-dump \(name)"] 62classDump.standardOutput = pipe 63 64// Redirect the output 65let outHandle = pipe.fileHandleForReading 66 67var output = "" 68 69// Put the output in the string output 70outHandle.readabilityHandler = { pipe in 71 if let line = String(data: pipe.availableData, encoding: String.Encoding.utf8) { 72 output.append(line) 73 } else { 74 print("Error decoding data: \(pipe.availableData)") 75 } 76} 77 78// Run it and wait for it to finish 79classDump.launch() 80classDump.waitUntilExit() 81 82var classes: [(class: String, superclass: String)] = [] 83 84// Begin ugly string parsing code 85while output.contains("@interface") { 86 let interfaceRange = output.range(of: "@interface")! 87 output.removeSubrange(output.startIndex ... interfaceRange.upperBound) 88 if let space = output.range(of: " : ") { 89 let className = output[output.startIndex ..< space.lowerBound] 90 91 output.removeSubrange(output.startIndex ..< space.upperBound) 92 93 var endOfSuperclass: String.Index! 94 let nextNewline = output.range(of: "\n") 95 let nextProtocolConformance = output.range(of: " <") 96 if nextNewline != nil && nextProtocolConformance != nil { 97 endOfSuperclass = nextNewline!.lowerBound < nextProtocolConformance!.lowerBound ? nextNewline!.lowerBound : nextProtocolConformance!.lowerBound 98 } else if nextNewline != nil { 99 endOfSuperclass = nextNewline!.lowerBound 100 } else if nextProtocolConformance != nil { 101 endOfSuperclass = nextProtocolConformance!.lowerBound 102 } else { 103 fatalError("Failed to detect superclass: \(className)") 104 } 105 let superclass = output[output.startIndex ..< endOfSuperclass] 106 107 classes.append((class: String(className), superclass: String(superclass))) 108 } 109} 110// End ugly string parsing code 111 112// Create destination folders if they don't exist 113try FileManager.default.createDirectory(atPath: outputDirectory, withIntermediateDirectories: true) 114try FileManager.default.createDirectory(atPath: outputDirectory + "/Headers", withIntermediateDirectories: true) 115try FileManager.default.createDirectory(atPath: outputDirectory + "/Sources", withIntermediateDirectories: true) 116 117// Emit master header 118var mh = copyright 119mh += "#import <Foundation/Foundation.h>\n" 120 121// Generate headers and sources for each class 122for classEntry in classes { 123 124 mh += "#import <\(moduleName)/\(classEntry.class).h>\n" 125 126 var header = copyright 127 128 header += "@interface \(classEntry.class) : \(classEntry.superclass)\n\n" 129 130 header += "@end\n" 131 132 var implementation = copyright 133 134 implementation += "#import <\(moduleName)/\(moduleName).h>\n\n" 135 136 implementation += "@implementation \(classEntry.class)\n\n" 137 138 implementation += "- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {\n" 139 implementation += " return [NSMethodSignature signatureWithObjCTypes: \"v@:\"];\n" 140 implementation += "}\n\n" 141 142 implementation += "- (void)forwardInvocation:(NSInvocation *)anInvocation {\n" 143 implementation += " NSLog(@\"Stub called: %@ in %@\", NSStringFromSelector([anInvocation selector]), [self class]);\n" 144 implementation += "}\n\n" 145 146 implementation += "@end\n" 147 148 try header.write(toFile: outputDirectory + "/Headers/" + classEntry.class + ".h", atomically: false, encoding: String.Encoding.utf8) 149 try implementation.write(toFile: outputDirectory + "/Sources/" + classEntry.class + ".m", atomically: false, encoding: String.Encoding.utf8) 150} 151 152try mh.write(toFile: outputDirectory + "/Headers/" + moduleName + ".h", atomically: false, encoding: String.Encoding.utf8)