Skip to content

Commit d2d2be7

Browse files
committed
Use a better Xcode detection
1 parent 41d3973 commit d2d2be7

File tree

1 file changed

+32
-22
lines changed

1 file changed

+32
-22
lines changed

Sources/CLTLogger.swift

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import Logging
1919
The idea is: “usable” text (text that is actually what the user asked for when launching your tool) should be output to stdout,
2020
presumably using `print`, the rest should be on stderr.
2121
If needed you can setup the logger to use any fd, the logger will simply `write(2)` to it.
22-
+ Ouptut has special control chars for colors if program is not compiled w/ Xcode and output fd is a tty.
22+
+ Ouptut has special control chars for colors if the output fd is a tty and Xcode is not detected.
2323
You can force using or force not using colors.
2424
+ If the write syscall fails, the log is lost (or partially lost; interrupts are retried; see SystemPackage for more info).
2525
+ You can configure the logger not to automatically add a new line after each message.
@@ -141,7 +141,7 @@ public struct CLTLogger : LogHandler {
141141
switch logPrefixStyle {
142142
case .none: constantsByLevel = [:]
143143
case .text: constantsByLevel = CLTLogger.defaultConstantsByLogLevelForText
144-
case .emoji: constantsByLevel = CLTLogger.defaultConstantsByLogLevelForEmoji
144+
case .emoji: constantsByLevel = CLTLogger.defaultConstantsByLogLevelForEmoji(on: fd)
145145
case .color: constantsByLevel = CLTLogger.defaultConstantsByLogLevelForColors
146146
case .auto: fatalError()
147147
}
@@ -196,25 +196,35 @@ public struct CLTLogger : LogHandler {
196196
case "color": return .color
197197
case "emoji": return .emoji
198198
case "text": return .text
199-
default: (/* nop: The logger style is invalid, we infer the style as if the variable is not there. */)
199+
default: (/* nop: The logger style is invalid, we infer the style as if the variable were not there. */)
200200
}
201201
}
202-
let supportsColor = {
203-
if let s = getenv("__CFBundleIdentifier"), String(cString: s) == "com.apple.dt.Xcode" {
204-
/* Xcode runs the programs in a tty, but does not support colors. */
205-
return false
206-
}
207-
if isatty(fd.rawValue) != 0 {
208-
/* TODO: Check whether the tty actually supports colors.
209-
* Hint: `tput colors` is able to return the numbers of colors supported in the terminal. How does it do it? */
210-
return true
211-
}
212-
if let s = getenv("GITHUB_ACTIONS"), String(cString: s) == "true" {
213-
return true
202+
203+
/* * * The logging style is not defined specifically in the dedicated environment value: we try and detect a correct value depending on other environmental clues. * * */
204+
205+
/* Is the fd on which we write a tty?
206+
* Most ttys nowadays support colors, with a notable exception: Xcode. */
207+
if isatty(fd.rawValue) != 0 {
208+
/* Xcode detection: it ain’t trivial.
209+
* I found checking for the existence of the __XCODE_BUILT_PRODUCTS_DIR_PATHS env var to be a possible solution.
210+
* We could also probably check for the existence of the TERM env var: Xcode does not set it.
211+
* (When Package.swift is built we can check if the value of the __CFBundleIdentifier env var is "com.apple.dt.Xcode".)
212+
* The solution we’re currently using is to check whether the fd on which we write has a foreground process group as Xcode does not set one.
213+
* Note: If Xcode detection is changed here, it should also be changed in defaultConstantsByLogLevelForEmoji. */
214+
if tcgetpgrp(fd.rawValue) == -1 && errno == ENOTTY {
215+
/* We log using emojis in Xcode. */
216+
return .emoji
214217
}
215-
return false
218+
/* If the TERM env var is not set we assume colors are not supported and return the text logging style.
219+
* In theory we should use the curses database to check for colors (ncurses has the `has_colors` function for this). */
220+
return (getenv("TERM") == nil ? .text : .color)
216221
}
217-
return (supportsColor() ? .color : .emoji)
222+
if let s = getenv("GITHUB_ACTIONS"), String(cString: s) == "true" {
223+
/* GitHub does support colors. */
224+
return .color
225+
}
226+
/* Unknown case: we return the text logging style. */
227+
return .text
218228
}
219229

220230
/* Do _not_ use os_unfair_lock, apparently it is bad in Swift:
@@ -254,17 +264,17 @@ public extension CLTLogger {
254264
]
255265
}()
256266

257-
static var defaultConstantsByLogLevelForEmoji: [Logger.Level: Constants] = {
267+
static func defaultConstantsByLogLevelForEmoji(on fd: FileDescriptor) -> [Logger.Level: Constants] {
258268
func addMeta(_ str: String, _ padding: String) -> Constants {
259269
var str = str
260-
if let s = getenv("__CFBundleIdentifier"), String(cString: s) == "com.apple.dt.Xcode" {
261-
/* We’re in Xcode.
270+
if isatty(fd.rawValue) != 0, tcgetpgrp(fd.rawValue) == -1, errno == ENOTTY {
271+
/* We’re in Xcode (probably).
262272
* By default we do not do the emoji padding, unless explicitly asked to (`CLTLOGGER_TERMINAL_EMOJI` set to anything but “NO”). */
263273
if let s = getenv("CLTLOGGER_TERMINAL_EMOJI"), String(cString: s) != "NO" {
264274
str = str + padding
265275
}
266276
} else {
267-
/* We’re not in Xcode.
277+
/* We’re not in Xcode (probably).
268278
* By default we do the emoji padding, unless explicitly asked not to (`CLTLOGGER_TERMINAL_EMOJI` set to “NO”). */
269279
if let s = getenv("CLTLOGGER_TERMINAL_EMOJI"), String(cString: s) == "NO" {
270280
/*nop*/
@@ -291,7 +301,7 @@ public extension CLTLogger {
291301
.error: addMeta("❗️", ""),
292302
.critical: addMeta("‼️", " ")
293303
]
294-
}()
304+
}
295305

296306
/* Terminal does not support RGB colors, so we use 255-color palette. */
297307
static var defaultConstantsByLogLevelForColors: [Logger.Level: Constants] = {

0 commit comments

Comments
 (0)