@@ -97,6 +97,11 @@ fileprivate struct WorkspaceStateStorage {
97
97
let dependencies = try v4. object. dependencies. map { try Workspace . ManagedDependency ( $0) }
98
98
let artifacts = try v4. object. artifacts. map { try Workspace . ManagedArtifact ( $0) }
99
99
return ( dependencies: . init( dependencies) , artifacts: . init( artifacts) )
100
+ case 5 :
101
+ let v5 = try self . decoder. decode ( path: self . path, fileSystem: self . fileSystem, as: V5 . self)
102
+ let dependencies = try v5. object. dependencies. map { try Workspace . ManagedDependency ( $0) }
103
+ let artifacts = try v5. object. artifacts. map { try Workspace . ManagedArtifact ( $0) }
104
+ return ( dependencies: . init( dependencies) , artifacts: . init( artifacts) )
100
105
default :
101
106
throw StringError ( " unknown 'WorkspaceStateStorage' version ' \( version. version) ' at ' \( self . path) ' " )
102
107
}
@@ -109,7 +114,7 @@ fileprivate struct WorkspaceStateStorage {
109
114
}
110
115
111
116
try self . fileSystem. withLock ( on: self . path, type: . exclusive) {
112
- let storage = V4 ( dependencies: dependencies, artifacts: artifacts)
117
+ let storage = V5 ( dependencies: dependencies, artifacts: artifacts)
113
118
114
119
let data = try self . encoder. encode ( storage)
115
120
try self . fileSystem. writeFileContents ( self . path, data: data)
@@ -128,23 +133,25 @@ fileprivate struct WorkspaceStateStorage {
128
133
func fileExists( ) -> Bool {
129
134
return self . fileSystem. exists ( self . path)
130
135
}
136
+ }
131
137
138
+ extension WorkspaceStateStorage {
132
139
// version reader
133
140
struct Version : Codable {
134
141
let version : Int
135
142
}
143
+ }
136
144
137
- /// * 4: Artifacts.
138
- /// * 3: Package kind.
139
- /// * 2: Package identity.
140
- /// * 1: Initial version.
141
- // v4 storage format
142
- struct V4 : Codable {
145
+ // MARK: - V5 format
146
+
147
+ extension WorkspaceStateStorage {
148
+ // v5 storage format
149
+ struct V5 : Codable {
143
150
let version : Int
144
151
let object : Container
145
152
146
153
init ( dependencies: Workspace . ManagedDependencies , artifacts: Workspace . ManagedArtifacts ) {
147
- self . version = 4
154
+ self . version = 5
148
155
self . object = . init(
149
156
dependencies: dependencies. map { . init( $0) } . sorted { $0. packageRef. identity < $1. packageRef. identity } ,
150
157
artifacts: artifacts. map { . init( $0) } . sorted { $0. packageRef. identity < $1. packageRef. identity }
@@ -377,7 +384,7 @@ fileprivate struct WorkspaceStateStorage {
377
384
}
378
385
379
386
extension Workspace . ManagedDependency {
380
- fileprivate init ( _ dependency: WorkspaceStateStorage . V4 . Dependency ) throws {
387
+ fileprivate init ( _ dependency: WorkspaceStateStorage . V5 . Dependency ) throws {
381
388
try self . init (
382
389
packageRef: . init( dependency. packageRef) ,
383
390
state: dependency. state. underlying,
@@ -387,7 +394,7 @@ extension Workspace.ManagedDependency {
387
394
}
388
395
389
396
extension Workspace . ManagedArtifact {
390
- fileprivate init ( _ artifact: WorkspaceStateStorage . V4 . Artifact ) throws {
397
+ fileprivate init ( _ artifact: WorkspaceStateStorage . V5 . Artifact ) throws {
391
398
try self . init (
392
399
packageRef: . init( artifact. packageRef) ,
393
400
targetName: artifact. targetName,
@@ -398,7 +405,7 @@ extension Workspace.ManagedArtifact {
398
405
}
399
406
400
407
extension PackageModel . PackageReference {
401
- fileprivate init ( _ reference: WorkspaceStateStorage . V4 . PackageReference ) throws {
408
+ fileprivate init ( _ reference: WorkspaceStateStorage . V5 . PackageReference ) throws {
402
409
let identity = PackageIdentity . plain ( reference. identity)
403
410
let kind : PackageModel . PackageReference . Kind
404
411
switch reference. kind {
@@ -425,6 +432,245 @@ extension PackageModel.PackageReference {
425
432
}
426
433
}
427
434
435
+ extension CheckoutState {
436
+ fileprivate init ( _ state: WorkspaceStateStorage . V5 . Dependency . State . CheckoutInfo ) throws {
437
+ let revision : Revision = . init( identifier: state. revision)
438
+ if let branch = state. branch {
439
+ self = . branch( name: branch, revision: revision)
440
+ } else if let version = state. version {
441
+ self = try . version( Version ( versionString: version) , revision: revision)
442
+ } else {
443
+ self = . revision( revision)
444
+ }
445
+ }
446
+ }
447
+
448
+
449
+ // MARK: - V1...4 format
450
+
451
+ extension WorkspaceStateStorage {
452
+ /// * 4: Artifacts.
453
+ /// * 3: Package kind.
454
+ /// * 2: Package identity.
455
+ /// * 1: Initial version.
456
+ // v4 storage format
457
+ struct V4 : Decodable {
458
+ let version : Int
459
+ let object : Container
460
+
461
+ struct Container : Decodable {
462
+ var dependencies : [ Dependency ]
463
+ var artifacts : [ Artifact ]
464
+ }
465
+
466
+ struct Dependency : Decodable {
467
+ let packageRef : PackageReference
468
+ let state : State
469
+ let subpath : String
470
+
471
+ init ( packageRef: PackageReference , state: State , subpath: String ) {
472
+ self . packageRef = packageRef
473
+ self . state = state
474
+ self . subpath = subpath
475
+ }
476
+
477
+ init ( from decoder: Decoder ) throws {
478
+ let container = try decoder. container ( keyedBy: CodingKeys . self)
479
+ let packageRef = try container. decode ( PackageReference . self, forKey: . packageRef)
480
+ let subpath = try container. decode ( String . self, forKey: . subpath)
481
+ let basedOn = try container. decode ( Dependency ? . self, forKey: . basedOn)
482
+ let state = try State . decode (
483
+ container: container. nestedContainer ( keyedBy: State . CodingKeys. self, forKey: . state) ,
484
+ packageRef: packageRef,
485
+ basedOn: basedOn
486
+ )
487
+
488
+ self . init (
489
+ packageRef: packageRef,
490
+ state: state,
491
+ subpath: subpath
492
+ )
493
+ }
494
+
495
+ enum CodingKeys : CodingKey {
496
+ case packageRef
497
+ case state
498
+ case subpath
499
+ case basedOn
500
+ }
501
+
502
+ struct State {
503
+ let underlying : Workspace . ManagedDependency . State
504
+
505
+ init ( underlying: Workspace . ManagedDependency . State ) {
506
+ self . underlying = underlying
507
+ }
508
+
509
+ static func decode( container: KeyedDecodingContainer < Self . CodingKeys > , packageRef: PackageReference , basedOn: Dependency ? ) throws -> State {
510
+ let kind = try container. decode ( String . self, forKey: . name)
511
+ switch kind {
512
+ case " local " :
513
+ return try self . init ( underlying: . local( . init( validating: packageRef. location) ) )
514
+ case " checkout " :
515
+ let checkout = try container. decode ( CheckoutInfo . self, forKey: . checkoutState)
516
+ return try self . init ( underlying: . checkout( . init( checkout) ) )
517
+ case " edited " :
518
+ let path = try container. decode ( AbsolutePath ? . self, forKey: . path)
519
+ return try self . init ( underlying: . edited( basedOn: basedOn. map { try . init( $0) } , unmanagedPath: path) )
520
+ default :
521
+ throw InternalError ( " unknown checkout state \( kind) " )
522
+ }
523
+ }
524
+
525
+ enum CodingKeys : CodingKey {
526
+ case name
527
+ case path
528
+ case checkoutState
529
+ }
530
+
531
+ struct CheckoutInfo : Codable {
532
+ let revision : String
533
+ let branch : String ?
534
+ let version : String ?
535
+
536
+ init ( _ state: CheckoutState ) {
537
+ switch state {
538
+ case . version( let version, let revision) :
539
+ self . version = version. description
540
+ self . branch = nil
541
+ self . revision = revision. identifier
542
+ case . branch( let branch, let revision) :
543
+ self . version = nil
544
+ self . branch = branch
545
+ self . revision = revision. identifier
546
+ case . revision( let revision) :
547
+ self . version = nil
548
+ self . branch = nil
549
+ self . revision = revision. identifier
550
+ }
551
+ }
552
+ }
553
+ }
554
+ }
555
+
556
+ struct Artifact : Decodable {
557
+ let packageRef : PackageReference
558
+ let targetName : String
559
+ let source : Source
560
+ let path : String
561
+
562
+ struct Source : Decodable {
563
+ let underlying : Workspace . ManagedArtifact . Source
564
+
565
+ init ( underlying: Workspace . ManagedArtifact . Source ) {
566
+ self . underlying = underlying
567
+ }
568
+
569
+ init ( from decoder: Decoder ) throws {
570
+ let container = try decoder. container ( keyedBy: CodingKeys . self)
571
+ let kind = try container. decode ( String . self, forKey: . type)
572
+ switch kind {
573
+ case " local " :
574
+ let checksum = try container. decodeIfPresent ( String . self, forKey: . checksum)
575
+ self . init ( underlying: . local( checksum: checksum) )
576
+ case " remote " :
577
+ let url = try container. decode ( String . self, forKey: . url)
578
+ let checksum = try container. decode ( String . self, forKey: . checksum)
579
+ self . init ( underlying: . remote( url: url, checksum: checksum) )
580
+ default :
581
+ throw InternalError ( " unknown checkout state \( kind) " )
582
+ }
583
+ }
584
+
585
+ enum CodingKeys : CodingKey {
586
+ case type
587
+ case url
588
+ case checksum
589
+ }
590
+ }
591
+ }
592
+
593
+ struct PackageReference : Decodable {
594
+ let identity : String
595
+ let kind : String
596
+ let location : String
597
+ let name : String
598
+
599
+ init ( from decoder: Decoder ) throws {
600
+ let container = try decoder. container ( keyedBy: CodingKeys . self)
601
+ self . identity = try container. decode ( String . self, forKey: . identity)
602
+ self . kind = try container. decode ( String . self, forKey: . kind)
603
+ self . name = try container. decode ( String . self, forKey: . name)
604
+ if let location = try container. decodeIfPresent ( String . self, forKey: . location) {
605
+ self . location = location
606
+ } else if let path = try container. decodeIfPresent ( String . self, forKey: . path) {
607
+ self . location = path
608
+ } else {
609
+ throw StringError ( " invalid package ref, missing location and path " )
610
+ }
611
+ }
612
+
613
+ enum CodingKeys : CodingKey {
614
+ case identity
615
+ case kind
616
+ case location
617
+ case path
618
+ case name
619
+ }
620
+ }
621
+ }
622
+ }
623
+
624
+ extension Workspace . ManagedDependency {
625
+ fileprivate init ( _ dependency: WorkspaceStateStorage . V4 . Dependency ) throws {
626
+ try self . init (
627
+ packageRef: . init( dependency. packageRef) ,
628
+ state: dependency. state. underlying,
629
+ subpath: RelativePath ( dependency. subpath)
630
+ )
631
+ }
632
+ }
633
+
634
+ extension Workspace . ManagedArtifact {
635
+ fileprivate init ( _ artifact: WorkspaceStateStorage . V4 . Artifact ) throws {
636
+ try self . init (
637
+ packageRef: . init( artifact. packageRef) ,
638
+ targetName: artifact. targetName,
639
+ source: artifact. source. underlying,
640
+ path: AbsolutePath ( artifact. path)
641
+ )
642
+ }
643
+ }
644
+
645
+ extension PackageModel . PackageReference {
646
+ fileprivate init ( _ reference: WorkspaceStateStorage . V4 . PackageReference ) throws {
647
+ let identity = PackageIdentity . plain ( reference. identity)
648
+ let kind : PackageModel . PackageReference . Kind
649
+ switch reference. kind {
650
+ case " root " :
651
+ kind = try . root( . init( validating: reference. location) )
652
+ case " local " :
653
+ kind = try . fileSystem( . init( validating: reference. location) )
654
+ case " remote " :
655
+ if let path = try ? AbsolutePath ( validating: reference. location) {
656
+ kind = . localSourceControl( path)
657
+ } else if let url = URL ( string: reference. location) {
658
+ kind = . remoteSourceControl( url)
659
+ } else {
660
+ throw StringError ( " invalid package kind \( reference. kind) " )
661
+ }
662
+ default :
663
+ throw StringError ( " invalid package kind \( reference. kind) " )
664
+ }
665
+
666
+ self . init (
667
+ identity: identity,
668
+ kind: kind,
669
+ name: reference. name
670
+ )
671
+ }
672
+ }
673
+
428
674
extension CheckoutState {
429
675
fileprivate init ( _ state: WorkspaceStateStorage . V4 . Dependency . State . CheckoutInfo ) throws {
430
676
let revision : Revision = . init( identifier: state. revision)
0 commit comments