mirror of
https://github.com/yonaskolb/XcodeGen.git
synced 2026-03-18 20:02:25 +00:00
rename to cache and refactor
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
import Foundation
|
||||
import ProjectSpec
|
||||
|
||||
|
||||
public class CacheFile {
|
||||
|
||||
public let string: String
|
||||
|
||||
init?(version: Version, projectDictionary: [String: Any], project: Project) throws {
|
||||
|
||||
guard #available(OSX 10.13, *) else { return nil }
|
||||
|
||||
let files = Array(Set(project.allFiles))
|
||||
.map { $0.byRemovingBase(path: project.basePath).string }
|
||||
.sorted { $0.localizedStandardCompare($1) == .orderedAscending }
|
||||
.joined(separator: "\n")
|
||||
|
||||
let data = try JSONSerialization.data(withJSONObject: projectDictionary, options: [.sortedKeys, .prettyPrinted])
|
||||
let spec = String(data: data, encoding: .utf8)!
|
||||
|
||||
string = """
|
||||
# XCODEGEN VERSION
|
||||
\(version)
|
||||
|
||||
# SPEC
|
||||
\(spec)
|
||||
|
||||
# FILES
|
||||
\(files)"
|
||||
|
||||
"""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
// To date, adding CommonCrypto to a Swift framework is problematic. See:
|
||||
// http://stackoverflow.com/questions/25248598/importing-commoncrypto-in-a-swift-framework
|
||||
// We're using a subset and modified version of CryptoSwift as an alternative.
|
||||
// The following is an altered source version that only includes MD5. The original software can be found at:
|
||||
// https://github.com/krzyzanowskim/CryptoSwift
|
||||
// This is the original copyright notice:
|
||||
|
||||
/*
|
||||
Copyright (C) 2014 Marcin Krzyżanowski <marcin.krzyzanowski@gmail.com>
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
|
||||
- The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
|
||||
- Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
- This notice may not be removed or altered from any source or binary distribution.
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
|
||||
extension String {
|
||||
public var md5: String {
|
||||
if let data = data(using: .utf8, allowLossyConversion: true) {
|
||||
let message = data.withUnsafeBytes { bytes -> [UInt8] in
|
||||
return Array(UnsafeBufferPointer(start: bytes, count: data.count))
|
||||
}
|
||||
|
||||
let MD5Calculator = MD5(message)
|
||||
let MD5Data = MD5Calculator.calculate()
|
||||
|
||||
var MD5String = String()
|
||||
for c in MD5Data {
|
||||
MD5String += String(format: "%02x", c)
|
||||
}
|
||||
return MD5String
|
||||
|
||||
} else {
|
||||
return self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** array of bytes, little-endian representation */
|
||||
func arrayOfBytes<T>(_ value: T, length: Int? = nil) -> [UInt8] {
|
||||
let totalBytes = length ?? (MemoryLayout<T>.size * 8)
|
||||
|
||||
let valuePointer = UnsafeMutablePointer<T>.allocate(capacity: 1)
|
||||
valuePointer.pointee = value
|
||||
|
||||
let bytes = valuePointer.withMemoryRebound(to: UInt8.self, capacity: totalBytes) { (bytesPointer) -> [UInt8] in
|
||||
var bytes = [UInt8](repeating: 0, count: totalBytes)
|
||||
for j in 0 ..< min(MemoryLayout<T>.size, totalBytes) {
|
||||
bytes[totalBytes - 1 - j] = (bytesPointer + j).pointee
|
||||
}
|
||||
return bytes
|
||||
}
|
||||
|
||||
#if swift(>=4.1)
|
||||
valuePointer.deinitialize(count: 1)
|
||||
valuePointer.deallocate()
|
||||
#else
|
||||
valuePointer.deinitialize()
|
||||
valuePointer.deallocate(capacity: 1)
|
||||
#endif
|
||||
|
||||
return bytes
|
||||
}
|
||||
|
||||
extension Int {
|
||||
/** Array of bytes with optional padding (little-endian) */
|
||||
func bytes(_ totalBytes: Int = MemoryLayout<Int>.size) -> [UInt8] {
|
||||
return arrayOfBytes(self, length: totalBytes)
|
||||
}
|
||||
}
|
||||
|
||||
extension NSMutableData {
|
||||
/** Convenient way to append bytes */
|
||||
func appendBytes(_ arrayOfBytes: [UInt8]) {
|
||||
append(arrayOfBytes, length: arrayOfBytes.count)
|
||||
}
|
||||
}
|
||||
|
||||
protocol HashProtocol {
|
||||
var message: Array<UInt8> { get }
|
||||
|
||||
/** Common part for hash calculation. Prepare header data. */
|
||||
func prepare(_ len: Int) -> Array<UInt8>
|
||||
}
|
||||
|
||||
extension HashProtocol {
|
||||
func prepare(_ len: Int) -> Array<UInt8> {
|
||||
var tmpMessage = message
|
||||
|
||||
// Step 1. Append Padding Bits
|
||||
tmpMessage.append(0x80) // append one bit (UInt8 with one bit) to message
|
||||
|
||||
// append "0" bit until message length in bits ≡ 448 (mod 512)
|
||||
var msgLength = tmpMessage.count
|
||||
var counter = 0
|
||||
|
||||
while msgLength % len != (len - 8) {
|
||||
counter += 1
|
||||
msgLength += 1
|
||||
}
|
||||
|
||||
tmpMessage += Array<UInt8>(repeating: 0, count: counter)
|
||||
return tmpMessage
|
||||
}
|
||||
}
|
||||
|
||||
func toUInt32Array(_ slice: ArraySlice<UInt8>) -> Array<UInt32> {
|
||||
var result = Array<UInt32>()
|
||||
result.reserveCapacity(16)
|
||||
|
||||
for idx in stride(from: slice.startIndex, to: slice.endIndex, by: MemoryLayout<UInt32>.size) {
|
||||
let d0 = UInt32(slice[idx.advanced(by: 3)]) << 24
|
||||
let d1 = UInt32(slice[idx.advanced(by: 2)]) << 16
|
||||
let d2 = UInt32(slice[idx.advanced(by: 1)]) << 8
|
||||
let d3 = UInt32(slice[idx])
|
||||
let val: UInt32 = d0 | d1 | d2 | d3
|
||||
|
||||
result.append(val)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
struct BytesIterator: IteratorProtocol {
|
||||
let chunkSize: Int
|
||||
let data: [UInt8]
|
||||
|
||||
init(chunkSize: Int, data: [UInt8]) {
|
||||
self.chunkSize = chunkSize
|
||||
self.data = data
|
||||
}
|
||||
|
||||
var offset = 0
|
||||
|
||||
mutating func next() -> ArraySlice<UInt8>? {
|
||||
let end = min(chunkSize, data.count - offset)
|
||||
let result = data[offset ..< offset + end]
|
||||
offset += result.count
|
||||
return result.count > 0 ? result : nil
|
||||
}
|
||||
}
|
||||
|
||||
struct BytesSequence: Sequence {
|
||||
let chunkSize: Int
|
||||
let data: [UInt8]
|
||||
|
||||
func makeIterator() -> BytesIterator {
|
||||
return BytesIterator(chunkSize: chunkSize, data: data)
|
||||
}
|
||||
}
|
||||
|
||||
func rotateLeft(_ value: UInt32, bits: UInt32) -> UInt32 {
|
||||
return ((value << bits) & 0xFFFF_FFFF) | (value >> (32 - bits))
|
||||
}
|
||||
|
||||
class MD5: HashProtocol {
|
||||
static let size = 16 // 128 / 8
|
||||
let message: [UInt8]
|
||||
|
||||
init(_ message: [UInt8]) {
|
||||
self.message = message
|
||||
}
|
||||
|
||||
/** specifies the per-round shift amounts */
|
||||
private let shifts: [UInt32] = [
|
||||
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
|
||||
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
|
||||
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
|
||||
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
|
||||
]
|
||||
|
||||
/** binary integer part of the sines of integers (Radians) */
|
||||
private let sines: [UInt32] = [
|
||||
0xD76A_A478, 0xE8C7_B756, 0x2420_70DB, 0xC1BD_CEEE,
|
||||
0xF57C_0FAF, 0x4787_C62A, 0xA830_4613, 0xFD46_9501,
|
||||
0x6980_98D8, 0x8B44_F7AF, 0xFFFF_5BB1, 0x895C_D7BE,
|
||||
0x6B90_1122, 0xFD98_7193, 0xA679_438E, 0x49B4_0821,
|
||||
0xF61E_2562, 0xC040_B340, 0x265E_5A51, 0xE9B6_C7AA,
|
||||
0xD62F_105D, 0x0244_1453, 0xD8A1_E681, 0xE7D3_FBC8,
|
||||
0x21E1_CDE6, 0xC337_07D6, 0xF4D5_0D87, 0x455A_14ED,
|
||||
0xA9E3_E905, 0xFCEF_A3F8, 0x676F_02D9, 0x8D2A_4C8A,
|
||||
0xFFFA_3942, 0x8771_F681, 0x6D9D_6122, 0xFDE5_380C,
|
||||
0xA4BE_EA44, 0x4BDE_CFA9, 0xF6BB_4B60, 0xBEBF_BC70,
|
||||
0x289B_7EC6, 0xEAA1_27FA, 0xD4EF_3085, 0x4881D05,
|
||||
0xD9D4_D039, 0xE6DB_99E5, 0x1FA2_7CF8, 0xC4AC_5665,
|
||||
0xF429_2244, 0x432A_FF97, 0xAB94_23A7, 0xFC93_A039,
|
||||
0x655B_59C3, 0x8F0C_CC92, 0xFFEF_F47D, 0x8584_5DD1,
|
||||
0x6FA8_7E4F, 0xFE2C_E6E0, 0xA301_4314, 0x4E08_11A1,
|
||||
0xF753_7E82, 0xBD3A_F235, 0x2AD7_D2BB, 0xEB86_D391,
|
||||
]
|
||||
|
||||
private let hashes: [UInt32] = [0x6745_2301, 0xEFCD_AB89, 0x98BA_DCFE, 0x1032_5476]
|
||||
|
||||
func calculate() -> [UInt8] {
|
||||
var tmpMessage = prepare(64)
|
||||
tmpMessage.reserveCapacity(tmpMessage.count + 4)
|
||||
|
||||
// hash values
|
||||
var hh = hashes
|
||||
|
||||
// Step 2. Append Length a 64-bit representation of lengthInBits
|
||||
let lengthInBits = (message.count * 8)
|
||||
let lengthBytes = lengthInBits.bytes(64 / 8)
|
||||
tmpMessage += lengthBytes.reversed()
|
||||
|
||||
// Process the message in successive 512-bit chunks:
|
||||
let chunkSizeBytes = 512 / 8 // 64
|
||||
|
||||
for chunk in BytesSequence(chunkSize: chunkSizeBytes, data: tmpMessage) {
|
||||
// break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15
|
||||
var M = toUInt32Array(chunk)
|
||||
assert(M.count == 16, "Invalid array")
|
||||
|
||||
// Initialize hash value for this chunk:
|
||||
var A: UInt32 = hh[0]
|
||||
var B: UInt32 = hh[1]
|
||||
var C: UInt32 = hh[2]
|
||||
var D: UInt32 = hh[3]
|
||||
|
||||
var dTemp: UInt32 = 0
|
||||
|
||||
// Main loop
|
||||
for j in 0 ..< sines.count {
|
||||
var g = 0
|
||||
var F: UInt32 = 0
|
||||
|
||||
switch j {
|
||||
case 0 ... 15:
|
||||
F = (B & C) | ((~B) & D)
|
||||
g = j
|
||||
break
|
||||
case 16 ... 31:
|
||||
F = (D & B) | (~D & C)
|
||||
g = (5 * j + 1) % 16
|
||||
break
|
||||
case 32 ... 47:
|
||||
F = B ^ C ^ D
|
||||
g = (3 * j + 5) % 16
|
||||
break
|
||||
case 48 ... 63:
|
||||
F = C ^ (B | (~D))
|
||||
g = (7 * j) % 16
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
dTemp = D
|
||||
D = C
|
||||
C = B
|
||||
B = B &+ rotateLeft((A &+ F &+ sines[j] &+ M[g]), bits: shifts[j])
|
||||
A = dTemp
|
||||
}
|
||||
|
||||
hh[0] = hh[0] &+ A
|
||||
hh[1] = hh[1] &+ B
|
||||
hh[2] = hh[2] &+ C
|
||||
hh[3] = hh[3] &+ D
|
||||
}
|
||||
|
||||
var result = [UInt8]()
|
||||
result.reserveCapacity(hh.count / 4)
|
||||
|
||||
hh.forEach {
|
||||
let itemLE = $0.littleEndian
|
||||
let r1 = UInt8(itemLE & 0xFF)
|
||||
let r2 = UInt8((itemLE >> 8) & 0xFF)
|
||||
let r3 = UInt8((itemLE >> 16) & 0xFF)
|
||||
let r4 = UInt8((itemLE >> 24) & 0xFF)
|
||||
result += [r1, r2, r3, r4]
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:enable all
|
||||
@@ -0,0 +1,40 @@
|
||||
import Foundation
|
||||
import JSONUtilities
|
||||
import PathKit
|
||||
import ProjectSpec
|
||||
import xcodeproj
|
||||
import Yams
|
||||
|
||||
public class SpecLoader {
|
||||
|
||||
var project: Project!
|
||||
private var projectDictionary: [String: Any]?
|
||||
let version: Version
|
||||
let cacheFilePath: Path?
|
||||
|
||||
public init(version: Version, cacheFilePath: Path? = nil) {
|
||||
self.version = version
|
||||
self.cacheFilePath = cacheFilePath
|
||||
}
|
||||
|
||||
public func loadProject(path: Path) throws -> Project {
|
||||
let dictionary = try Project.loadDictionary(path: path)
|
||||
let project = try Project(basePath: path.parent(), jsonDictionary: dictionary)
|
||||
|
||||
self.project = project
|
||||
self.projectDictionary = dictionary
|
||||
|
||||
return project
|
||||
}
|
||||
|
||||
public func generateCacheFile() throws -> CacheFile? {
|
||||
guard let projectDictionary = projectDictionary,
|
||||
let project = project else {
|
||||
return nil
|
||||
}
|
||||
return try CacheFile(version: version,
|
||||
projectDictionary: projectDictionary,
|
||||
project: project)
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user