blob: 87f54b5eacca69055be52f80cb1b1e98bb114376 [file] [log] [blame]
// Copyright 2018 The Tulsi Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
protocol Pythonable {
func toPython(_ indentation: String) -> String
}
enum PythonSettings {
static let doubleIndent: String = " "
}
extension Dictionary where Key == String, Value: Pythonable {
func toPython(_ indentation: String) -> String {
guard !isEmpty else { return "{}" }
let nestedIndentation = "\(indentation)\(PythonSettings.doubleIndent)"
var script = "{\n"
for (key, value) in self {
script += """
\(nestedIndentation)\(key.toPython(nestedIndentation)): \(value.toPython(nestedIndentation)),
"""
}
script += "\(indentation)}"
return script
}
}
// TODO(tulsi-team): When we update to Swift 4.2, delete this in favor of conditional conformances.
extension Dictionary where Key == String, Value == [String] {
func toPython(_ indentation: String) -> String {
guard !isEmpty else { return "{}" }
let nestedIndentation = "\(indentation)\(PythonSettings.doubleIndent)"
var script = "{\n"
for (key, value) in self {
script += """
\(nestedIndentation)\(key.toPython(nestedIndentation)): \(value.toPython(nestedIndentation)),
"""
}
script += "\(indentation)}"
return script
}
}
extension Array where Element: Pythonable {
func toPython(_ indentation: String) -> String {
guard !isEmpty else { return "[]" }
var script = "[\n"
for value in self {
script += """
\(indentation)\(PythonSettings.doubleIndent)\(value.toPython("")),
"""
}
script += "\(indentation)]"
return script
}
}
extension Set where Element: Pythonable {
func toPython(_ indentation: String) -> String {
guard !isEmpty else { return "set()" }
var script = "set([\n"
for value in self {
script += """
\(indentation)\(PythonSettings.doubleIndent)\(value.toPython("")),
"""
}
script += "\(indentation)])"
return script
}
}
extension String: Pythonable {
func toPython(_ indentation: String) -> String {
guard self.contains("'") else { return "'\(self)'"}
let escapedStr = self.replacingOccurrences(of: "'", with: "\\'")
return "'\(escapedStr)'"
}
}
class BazelFlags: Equatable, Pythonable {
public let startup: [String]
public let build: [String]
public convenience init(startupStr: String, buildStr: String) {
self.init(startup: startupStr.components(separatedBy: " "),
build: buildStr.components(separatedBy: " "))
}
public init(startup: [String] = [], build: [String] = []) {
self.startup = startup.filter { !$0.isEmpty }
self.build = build.filter { !$0.isEmpty }
}
var isEmpty: Bool {
return startup.isEmpty && build.isEmpty
}
func toPython(_ indentation: String) -> String {
guard !self.isEmpty else { return "BazelFlags()" }
let nestedIndentation = "\(indentation)\(PythonSettings.doubleIndent)"
return """
BazelFlags(
\(nestedIndentation)startup = \(startup.toPython(nestedIndentation)),
\(nestedIndentation)build = \(build.toPython(nestedIndentation)),
\(indentation))
"""
}
static func ==(lhs: BazelFlags, rhs: BazelFlags) -> Bool {
return lhs.startup == rhs.startup && lhs.build == rhs.build
}
static func +(lhs: BazelFlags, rhs: BazelFlags) -> BazelFlags {
return BazelFlags(startup: lhs.startup + rhs.startup,
build: lhs.build + rhs.build)
}
}
class BazelFlagsSet: Equatable, Pythonable {
public let debug: BazelFlags
public let release: BazelFlags
public convenience init(startupFlags: [String] = [], buildFlags: [String] = []) {
self.init(common: BazelFlags(startup: startupFlags, build: buildFlags))
}
public init(debug: BazelFlags = BazelFlags(),
release: BazelFlags = BazelFlags(),
common: BazelFlags = BazelFlags()) {
self.debug = debug + common
self.release = release + common
}
var isEmpty: Bool {
return debug.isEmpty && release.isEmpty
}
func getFlags(forDebug: Bool = true) -> BazelFlags {
return forDebug ? debug : release
}
func toPython(_ indentation: String) -> String {
guard !isEmpty else { return "BazelFlagsSet()" }
let nestedIndentation = "\(indentation)\(PythonSettings.doubleIndent)"
// If debug == release we don't need to specify the same flags twice.
guard debug != release else {
return """
BazelFlagsSet(
\(nestedIndentation)flags = \(debug.toPython(nestedIndentation)),
\(indentation))
"""
}
return """
BazelFlagsSet(
\(nestedIndentation)debug = \(debug.toPython(nestedIndentation)),
\(nestedIndentation)release = \(release.toPython(nestedIndentation)),
\(indentation))
"""
}
static func ==(lhs: BazelFlagsSet, rhs: BazelFlagsSet) -> Bool {
return lhs.debug == rhs.debug && lhs.release == rhs.release
}
static func +(lhs: BazelFlagsSet, rhs: BazelFlagsSet) -> BazelFlagsSet {
return BazelFlagsSet(debug: lhs.debug + rhs.debug,
release: lhs.release + rhs.release)
}
}
class BazelBuildSettings: Pythonable {
public let bazel: String
public let bazelExecRoot: String
public let defaultPlatformConfigIdentifier: String
public let platformConfigurationFlags: [String: [String]]
public let tulsiCacheAffectingFlagsSet: BazelFlagsSet
public let tulsiCacheSafeFlagSet: BazelFlagsSet
public let tulsiSwiftFlagSet: BazelFlagsSet
public let tulsiNonSwiftFlagSet: BazelFlagsSet
public let swiftFeatures: [String]
public let nonSwiftFeatures: [String]
/// Set of targets which depend (in some fashion) on Swift.
public let swiftTargets: Set<String>
public let projDefaultFlagSet: BazelFlagsSet
public let projTargetFlagSets: [String: BazelFlagsSet]
public static var platformConfigurationFlagsMap: [String: [String]] {
return PlatformConfiguration.allValidConfigurations.reduce(into: [String: [String]]()) { (dict, config) in
dict[config.identifier] = config.bazelFlags
}
}
public init(bazel: String,
bazelExecRoot: String,
defaultPlatformConfigIdentifier: String,
platformConfigurationFlags: [String: [String]]?,
swiftTargets: Set<String>,
tulsiCacheAffectingFlagsSet: BazelFlagsSet,
tulsiCacheSafeFlagSet: BazelFlagsSet,
tulsiSwiftFlagSet: BazelFlagsSet,
tulsiNonSwiftFlagSet: BazelFlagsSet,
swiftFeatures: [String],
nonSwiftFeatures: [String],
projDefaultFlagSet: BazelFlagsSet,
projTargetFlagSets: [String: BazelFlagsSet]) {
self.bazel = bazel
self.bazelExecRoot = bazelExecRoot
self.defaultPlatformConfigIdentifier = defaultPlatformConfigIdentifier
self.platformConfigurationFlags = platformConfigurationFlags ?? BazelBuildSettings.platformConfigurationFlagsMap
self.swiftTargets = swiftTargets
self.tulsiCacheAffectingFlagsSet = tulsiCacheAffectingFlagsSet
self.tulsiCacheSafeFlagSet = tulsiCacheSafeFlagSet
self.tulsiSwiftFlagSet = tulsiSwiftFlagSet
self.tulsiNonSwiftFlagSet = tulsiNonSwiftFlagSet
self.swiftFeatures = swiftFeatures
self.nonSwiftFeatures = nonSwiftFeatures
self.projDefaultFlagSet = projDefaultFlagSet
self.projTargetFlagSets = projTargetFlagSets
}
public func toPython(_ indentation: String) -> String {
let nestedIndentation = "\(indentation)\(PythonSettings.doubleIndent)"
return """
BazelBuildSettings(
\(nestedIndentation)\(bazel.toPython(nestedIndentation)),
\(nestedIndentation)\(bazelExecRoot.toPython(nestedIndentation)),
\(nestedIndentation)\(defaultPlatformConfigIdentifier.toPython(nestedIndentation)),
\(nestedIndentation)\(platformConfigurationFlags.toPython(nestedIndentation)),
\(nestedIndentation)\(swiftTargets.toPython(nestedIndentation)),
\(nestedIndentation)\(tulsiCacheAffectingFlagsSet.toPython(nestedIndentation)),
\(nestedIndentation)\(tulsiCacheSafeFlagSet.toPython(nestedIndentation)),
\(nestedIndentation)\(tulsiSwiftFlagSet.toPython(nestedIndentation)),
\(nestedIndentation)\(tulsiNonSwiftFlagSet.toPython(nestedIndentation)),
\(nestedIndentation)\(swiftFeatures.toPython(nestedIndentation)),
\(nestedIndentation)\(nonSwiftFeatures.toPython(nestedIndentation)),
\(nestedIndentation)\(projDefaultFlagSet.toPython(nestedIndentation)),
\(nestedIndentation)\(projTargetFlagSets.toPython(nestedIndentation)),
\(indentation))
"""
}
}