1
1
/*
2
2
This source file is part of the Swift.org open source project
3
3
4
- Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
4
+ Copyright (c) 2018 Apple Inc. and the Swift project authors
5
5
Licensed under Apache License v2.0 with Runtime Library Exception
6
6
7
7
See http://swift.org/LICENSE.txt for license information
@@ -13,12 +13,13 @@ import Glibc
13
13
#else
14
14
import Darwin. C
15
15
#endif
16
+ import Foundation
16
17
17
18
/// The description for a complete package.
18
19
public final class Package {
19
20
20
21
/// Represents a package dependency.
21
- public class Dependency {
22
+ public class Dependency : Encodable {
22
23
23
24
/// The dependency requirement.
24
25
public enum Requirement {
@@ -192,168 +193,136 @@ public enum SystemPackageProvider {
192
193
193
194
// MARK: Package JSON serialization
194
195
195
- extension SystemPackageProvider {
196
+ extension Package : Encodable {
197
+ private enum CodingKeys : CodingKey {
198
+ case name
199
+ case pkgConfig
200
+ case providers
201
+ case products
202
+ case dependencies
203
+ case targets
204
+ case swiftLanguageVersions
205
+ case cLanguageStandard
206
+ case cxxLanguageStandard
207
+ }
208
+
209
+ public func encode( to encoder: Encoder ) throws {
210
+ var container = encoder. container ( keyedBy: CodingKeys . self)
211
+ try container. encode ( name, forKey: . name)
212
+ try container. encode ( pkgConfig, forKey: . pkgConfig)
213
+ try container. encode ( providers, forKey: . providers)
214
+ try container. encode ( products, forKey: . products)
215
+ try container. encode ( dependencies, forKey: . dependencies)
216
+ try container. encode ( targets, forKey: . targets)
217
+ #if PACKAGE_DESCRIPTION_4
218
+ try container. encode ( swiftLanguageVersions? . map ( String . init) , forKey: . swiftLanguageVersions)
219
+ #else
220
+ try container. encode ( swiftLanguageVersions, forKey: . swiftLanguageVersions)
221
+ #endif
222
+ try container. encode ( cLanguageStandard, forKey: . cLanguageStandard)
223
+ try container. encode ( cxxLanguageStandard, forKey: . cxxLanguageStandard)
224
+ }
225
+ }
226
+
227
+ extension SystemPackageProvider : Encodable {
228
+ private enum CodingKeys : CodingKey {
229
+ case name
230
+ case values
231
+ }
196
232
197
- func toJSON( ) -> JSON {
198
- let name : String
199
- let values : [ String ]
233
+ private enum Name : String , Encodable {
234
+ case brew
235
+ case apt
236
+ }
200
237
238
+ public func encode( to encoder: Encoder ) throws {
239
+ var container = encoder. container ( keyedBy: CodingKeys . self)
201
240
#if PACKAGE_DESCRIPTION_4
202
241
switch self {
203
242
case . brewItem( let packages) :
204
- name = " brew "
205
- values = packages
243
+ try container . encode ( Name . brew, forKey : . name )
244
+ try container . encode ( packages, forKey : . values )
206
245
case . aptItem( let packages) :
207
- name = " apt "
208
- values = packages
246
+ try container . encode ( Name . apt, forKey : . name )
247
+ try container . encode ( packages, forKey : . values )
209
248
}
210
249
#else
211
250
switch self {
212
251
case . _brewItem( let packages) :
213
- name = " brew "
214
- values = packages
252
+ try container . encode ( Name . brew, forKey : . name )
253
+ try container . encode ( packages, forKey : . values )
215
254
case . _aptItem( let packages) :
216
- name = " apt "
217
- values = packages
255
+ try container . encode ( Name . apt, forKey : . name )
256
+ try container . encode ( packages, forKey : . values )
218
257
}
219
258
#endif
220
-
221
- return . dictionary( [
222
- " name " : . string( name) ,
223
- " values " : . array( values. map ( JSON . string) ) ,
224
- ] )
225
259
}
226
260
}
227
261
228
- extension Package {
229
- func toJSON( ) -> JSON {
230
- var dict : [ String : JSON ] = [ : ]
231
- dict [ " name " ] = . string( name)
232
- if let pkgConfig = self . pkgConfig {
233
- dict [ " pkgConfig " ] = . string( pkgConfig)
234
- }
235
- dict [ " dependencies " ] = . array( dependencies. map ( { $0. toJSON ( ) } ) )
236
- dict [ " targets " ] = . array( targets. map ( { $0. toJSON ( ) } ) )
237
- dict [ " products " ] = . array( products. map ( { $0. toJSON ( ) } ) )
238
- if let providers = self . providers {
239
- dict [ " providers " ] = . array( providers. map ( { $0. toJSON ( ) } ) )
240
- }
241
-
242
- let swiftLanguageVersionsString : [ String ] ?
243
- #if PACKAGE_DESCRIPTION_4
244
- swiftLanguageVersionsString = self . swiftLanguageVersions? . map ( String . init)
245
- #else
246
- swiftLanguageVersionsString = self . swiftLanguageVersions? . map ( { $0. toString ( ) } )
247
- #endif
248
- if let swiftLanguageVersions = swiftLanguageVersionsString {
249
- dict [ " swiftLanguageVersions " ] = . array( swiftLanguageVersions. map ( JSON . string) )
250
- }
251
-
252
- dict [ " cLanguageStandard " ] = cLanguageStandard? . toJSON ( ) ?? . null
253
- dict [ " cxxLanguageStandard " ] = cxxLanguageStandard? . toJSON ( ) ?? . null
254
- return . dictionary( dict)
262
+ extension Target . Dependency : Encodable {
263
+ private enum CodingKeys : CodingKey {
264
+ case type
265
+ case name
266
+ case package
255
267
}
256
- }
257
268
258
- extension Target {
259
- func toJSON( ) -> JSON {
260
- var dict : [ String : JSON ] = [
261
- " name " : . string( name) ,
262
- " type " : . string( type. rawValue) ,
263
- " publicHeadersPath " : publicHeadersPath. map ( JSON . string) ?? JSON . null,
264
- " dependencies " : . array( dependencies. map ( { $0. toJSON ( ) } ) ) ,
265
- " path " : path. map ( JSON . string) ?? JSON . null,
266
- " exclude " : . array( exclude. map ( JSON . string) ) ,
267
- " sources " : sources. map ( { JSON . array ( $0. map ( JSON . string) ) } ) ?? JSON . null,
268
- ]
269
- if let pkgConfig = self . pkgConfig {
270
- dict [ " pkgConfig " ] = . string( pkgConfig)
271
- }
272
- if let providers = self . providers {
273
- dict [ " providers " ] = . array( providers. map ( { $0. toJSON ( ) } ) )
274
- }
275
- return . dictionary( dict)
269
+ private enum Kind : String , Codable {
270
+ case target
271
+ case product
272
+ case byName = " byname "
276
273
}
277
- }
278
-
279
- extension Target . Dependency {
280
- func toJSON( ) -> JSON {
281
- var dict = [ String: JSON] ( )
282
274
275
+ public func encode( to encoder: Encoder ) throws {
276
+ var container = encoder. container ( keyedBy: CodingKeys . self)
283
277
#if PACKAGE_DESCRIPTION_4
284
278
switch self {
285
279
case . targetItem( let name) :
286
- dict [ " name " ] = . string ( name )
287
- dict [ " type " ] = . string ( " target " )
280
+ try container . encode ( Kind . target , forKey : . type )
281
+ try container . encode ( name , forKey : . name )
288
282
case . productItem( let name, let package ) :
289
- dict [ " name " ] = . string ( name )
290
- dict [ " type " ] = . string ( " product " )
291
- dict [ " package " ] = package . map ( JSON . string ) ?? . null
283
+ try container . encode ( Kind . product , forKey : . type )
284
+ try container . encode ( name , forKey : . name )
285
+ try container . encode ( package , forKey : . package )
292
286
case . byNameItem( let name) :
293
- dict [ " name " ] = . string ( name )
294
- dict [ " type " ] = . string ( " byname " )
287
+ try container . encode ( Kind . byName , forKey : . type )
288
+ try container . encode ( name , forKey : . name )
295
289
}
296
290
#else
297
291
switch self {
298
292
case . _targetItem( let name) :
299
- dict [ " name " ] = . string ( name )
300
- dict [ " type " ] = . string ( " target " )
293
+ try container . encode ( Kind . target , forKey : . type )
294
+ try container . encode ( name , forKey : . name )
301
295
case . _productItem( let name, let package ) :
302
- dict [ " name " ] = . string ( name )
303
- dict [ " type " ] = . string ( " product " )
304
- dict [ " package " ] = package . map ( JSON . string ) ?? . null
296
+ try container . encode ( Kind . product , forKey : . type )
297
+ try container . encode ( name , forKey : . name )
298
+ try container . encode ( package , forKey : . package )
305
299
case . _byNameItem( let name) :
306
- dict [ " name " ] = . string ( name )
307
- dict [ " type " ] = . string ( " byname " )
300
+ try container . encode ( Kind . byName , forKey : . type )
301
+ try container . encode ( name , forKey : . name )
308
302
}
309
303
#endif
310
-
311
- return . dictionary( dict)
312
304
}
313
305
}
314
306
315
307
// MARK: Package Dumping
316
308
317
- struct Errors {
318
- /// Storage to hold the errors.
319
- private var errors = [ String] ( )
320
-
321
- /// Adds error to global error array which will be serialized and dumped in
322
- /// JSON at exit.
323
- mutating func add( _ str: String ) {
324
- // FIXME: This will produce invalid JSON if string contains quotes.
325
- // Assert it for now and fix when we have escaping in JSON.
326
- assert ( !str. contains ( " \" " ) , " Error string shouldn't have quotes in it. " )
327
- errors += [ str]
328
- }
329
-
330
- func toJSON( ) -> JSON {
331
- return . array( errors. map ( JSON . string) )
332
- }
333
- }
334
-
335
309
func manifestToJSON( _ package : Package ) -> String {
336
- var dict : [ String : JSON ] = [ : ]
337
- dict [ " package " ] = package . toJSON ( )
338
- dict [ " errors " ] = errors. toJSON ( )
339
- return JSON . dictionary ( dict) . toString ( )
340
- }
310
+ struct Output : Encodable {
311
+ let package : Package
312
+ let errors : [ String ]
313
+ }
341
314
342
- // FIXME: This function is public to let other targets access JSON string
343
- // representation of the package without exposing the enum JSON defined in this
344
- // target because that'll leak to clients of PackageDescription i.e every
345
- // Package.swift file.
346
- public func jsonString( package : Package ) -> String {
347
- return package . toJSON ( ) . toString ( )
315
+ let encoder = JSONEncoder ( )
316
+ let data = try ! encoder. encode ( Output ( package : package , errors: errors) )
317
+ return String ( data: data, encoding: . utf8) !
348
318
}
349
319
350
- var errors = Errors ( )
320
+ var errors : [ String ] = [ ]
351
321
private var dumpInfo : ( package : Package , fileNo: Int32 ) ?
352
322
private func dumpPackageAtExit( _ package : Package , fileNo: Int32 ) {
353
323
func dump( ) {
354
324
guard let dumpInfo = dumpInfo else { return }
355
- let fd = fdopen ( dumpInfo. fileNo, " w " )
356
- guard fd != nil else { return }
325
+ guard let fd = fdopen ( dumpInfo. fileNo, " w " ) else { return }
357
326
fputs ( manifestToJSON ( dumpInfo. package ) , fd)
358
327
fclose ( fd)
359
328
}
0 commit comments