File: CoreDataCompiler.swift

package info (click to toggle)
swiftlang 6.2.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,856,264 kB
  • sloc: cpp: 9,995,718; ansic: 2,234,019; asm: 1,092,167; python: 313,940; objc: 82,726; f90: 80,126; lisp: 38,373; pascal: 25,580; sh: 20,378; ml: 5,058; perl: 4,751; makefile: 4,725; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (100 lines) | stat: -rw-r--r-- 5,359 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import SWBUtil
public import SWBCore
import SWBMacro

public final class CoreDataModelCompilerSpec : GenericCompilerSpec, SpecIdentifierType, @unchecked Sendable {
    public static let identifier = "com.apple.compilers.model.coredata"

    public override var supportsInstallHeaders: Bool {
        return true
    }

    public override var supportsInstallAPI: Bool {
        return true
    }

    public override func constructTasks(_ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate) async {
        // Construct the momc task.
        await constructCoreDataModelCompilerTasks(cbc, delegate)

        // Construct the code generation task.
        await constructCoreDataCodeGenerationTasks(cbc, delegate)
    }

    private func constructCoreDataModelCompilerTasks(_ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate) async {
        if cbc.scope.evaluate(BuiltinMacros.PACKAGE_RESOURCE_TARGET_KIND) == .regular {
            return
        }

        let components = cbc.scope.evaluate(BuiltinMacros.BUILD_COMPONENTS)
        if !components.contains("build") { return }

        // Invoke the generic implementation in CommandLineToolSpec to generate the momc task using the xcspec.
        await constructTasks(cbc, delegate, specialArgs: [])
    }

    private func constructCoreDataCodeGenerationTasks(_ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate) async {
        if cbc.scope.evaluate(BuiltinMacros.PACKAGE_RESOURCE_TARGET_KIND) == .resource {
            return
        }

        // Compute the output directory.
        let input = cbc.input
        let modelName = input.absolutePath.basenameWithoutSuffix
        let outputDir = cbc.scope.evaluate(BuiltinMacros.DERIVED_FILE_DIR).join("CoreDataGenerated").join(modelName).normalize()

        let inputs = [input.absolutePath]
        let ruleInfo = ["DataModelCodegen", input.absolutePath.str]
        var commandLine = await commandLineFromTemplate(cbc, delegate, optionContext: discoveredCommandLineToolSpecInfo(cbc.producer, cbc.scope, delegate)).map(\.asString)
        commandLine.insert(contentsOf: ["--action", "generate"] + (cbc.scope.evaluate(BuiltinMacros.SWIFT_VERSION).nilIfEmpty.map { ["--swift-version", $0] } ?? []), at: 1)
        commandLine[commandLine.count - 1] = outputDir.str

        // Ask the client delegate for the list of paths of generated files.
        let generatedFiles: [Path]
        do {
            // Mark the entire directory structure as being watched by the build system.
            delegate.access(path: input.absolutePath)

            generatedFiles = try await generatedFilePaths(cbc, delegate, commandLine: [commandLine[0]] + ["--dry-run"] + commandLine[1...], workingDirectory: cbc.producer.defaultWorkingDirectory, environment: self.environmentFromSpec(cbc, delegate).bindingsDictionary, executionDescription: "Compute data model \(input.absolutePath.basename) code generation output paths") { output in
                return output.unsafeStringValue.split(separator: "\n").map(Path.init).map { $0.prependingPrivatePrefixIfNeeded(otherPath: outputDir) }
            }
            guard !generatedFiles.isEmpty else {
                // If we were given an empty list of generated files, then there were just no files to be generated, so we return.
                // FIXME: Should we emit a generic error in this case?  Should the code generator ever return no files to be generated?
                return
            }
        } catch {
            delegate.error("Could not determine generated file paths for Core Data code generation: \(error)")
            return
        }

        // If we got this far, then we know we have a non-empty list of generated files.
        let outputs = generatedFiles

        // Declare the output files so they can be processed by the build phase which called us.
        for output in outputs {
            delegate.declareOutput(FileToBuild(absolutePath: output, inferringTypeUsing: cbc.producer))
        }

        delegate.createTask(type: self, ruleInfo: ruleInfo, commandLine: commandLine, environment: environmentFromSpec(cbc, delegate), workingDirectory: cbc.producer.defaultWorkingDirectory, inputs: inputs.map { delegate.createDirectoryTreeNode($0) }, outputs: outputs.map { delegate.createNode($0) }, execDescription: "Generate code for data model \(input.absolutePath.basename)", preparesForIndexing: true, enableSandboxing: enableSandboxing)
        // Also add the generated headers to the generated files headermap.
        for output in outputs {
            // Somehow the file type specification infrastructure doesn't define an 'isHeader' property, so we look at the file extension.
            if output.fileExtension == "h" {
                delegate.declareGeneratedSourceFile(output)
            }
        }
    }
}