Skip to content

Commit c6fc91b

Browse files
committed
Sync TSC changes from master
1 parent 8d20e43 commit c6fc91b

22 files changed

+996
-43
lines changed

swift-tools-support-core/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ else()
2121
endif()
2222
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
2323

24-
option(BUILD_SHARED_LIBS "Build shared libraryes by default" YES)
24+
option(BUILD_SHARED_LIBS "Build shared libraries by default" YES)
2525

2626
find_package(dispatch QUIET)
2727
find_package(Foundation QUIET)
28+
find_package(SQLite3 REQUIRED)
2829

2930
add_subdirectory(Sources)
3031
add_subdirectory(cmake/modules)
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Code of Conduct
2+
To be a truly great community, Swift.org needs to welcome developers from all walks of life,
3+
with different backgrounds, and with a wide range of experience. A diverse and friendly
4+
community will have more great ideas, more unique perspectives, and produce more great
5+
code. We will work diligently to make the Swift community welcoming to everyone.
6+
7+
To give clarity of what is expected of our members, Swift.org has adopted the code of conduct
8+
defined by [contributor-covenant.org](https://www.contributor-covenant.org). This document is used across many open source
9+
communities, and we think it articulates our values well. The full text is copied below:
10+
11+
### Contributor Code of Conduct v1.3
12+
As contributors and maintainers of this project, and in the interest of fostering an open and
13+
welcoming community, we pledge to respect all people who contribute through reporting
14+
issues, posting feature requests, updating documentation, submitting pull requests or patches,
15+
and other activities.
16+
17+
We are committed to making participation in this project a harassment-free experience for
18+
everyone, regardless of level of experience, gender, gender identity and expression, sexual
19+
orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or
20+
nationality.
21+
22+
Examples of unacceptable behavior by participants include:
23+
- The use of sexualized language or imagery
24+
- Personal attacks
25+
- Trolling or insulting/derogatory comments
26+
- Public or private harassment
27+
- Publishing other’s private information, such as physical or electronic addresses, without explicit permission
28+
- Other unethical or unprofessional conduct
29+
30+
Project maintainers have the right and responsibility to remove, edit, or reject comments,
31+
commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of
32+
Conduct, or to ban temporarily or permanently any contributor for other behaviors that they
33+
deem inappropriate, threatening, offensive, or harmful.
34+
35+
By adopting this Code of Conduct, project maintainers commit themselves to fairly and
36+
consistently applying these principles to every aspect of managing this project. Project
37+
maintainers who do not follow or enforce the Code of Conduct may be permanently removed
38+
from the project team.
39+
40+
This code of conduct applies both within project spaces and in public spaces when an
41+
individual is representing the project or its community.
42+
43+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by
44+
contacting a project maintainer at [[email protected]](mailto:[email protected]). All complaints will be reviewed and
45+
investigated and will result in a response that is deemed necessary and appropriate to the
46+
circumstances. Maintainers are obligated to maintain confidentiality with regard to the reporter
47+
of an incident.
48+
49+
*This policy is adapted from the Contributor Code of Conduct [version 1.3.0](http://contributor-covenant.org/version/1/3/0/).*
50+
51+
### Reporting
52+
A working group of community members is committed to promptly addressing any [reported
53+
issues](mailto:[email protected]). Working group members are volunteers appointed by the project lead, with a
54+
preference for individuals with varied backgrounds and perspectives. Membership is expected
55+
to change regularly, and may grow or shrink.

swift-tools-support-core/Sources/TSCBasic/CMakeLists.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ add_library(TSCBasic
4949
Thread.swift
5050
Tuple.swift
5151
misc.swift)
52+
target_compile_options(TSCBasic PUBLIC
53+
# Don't use GNU strerror_r on Android.
54+
"$<$<PLATFORM_ID:Android>:SHELL:-Xcc -U_GNU_SOURCE>"
55+
# Ignore secure function warnings on Windows.
56+
"$<$<PLATFORM_ID:Windows>:SHELL:-Xcc -D_CRT_SECURE_NO_WARNINGS>")
5257
target_link_libraries(TSCBasic PUBLIC
5358
TSCLibc)
5459
if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin)
@@ -67,9 +72,4 @@ install(TARGETS TSCBasic
6772
RUNTIME DESTINATION bin)
6873
endif()
6974

70-
# Don't use GNU strerror_r on Android.
71-
if(CMAKE_SYSTEM_NAME STREQUAL Android)
72-
target_compile_options(TSCBasic PUBLIC "SHELL:-Xcc -U_GNU_SOURCE")
73-
endif()
74-
7575
set_property(GLOBAL APPEND PROPERTY TSC_EXPORTS TSCBasic)

swift-tools-support-core/Sources/TSCBasic/CStringArray.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ public final class CStringArray {
2020

2121
/// Creates an instance from an array of strings.
2222
public init(_ array: [String]) {
23+
#if os(Windows)
24+
cArray = array.map({ $0.withCString({ _strdup($0) }) }) + [nil]
25+
#else
2326
cArray = array.map({ $0.withCString({ strdup($0) }) }) + [nil]
27+
#endif
2428
}
2529

2630
deinit {

swift-tools-support-core/Sources/TSCBasic/FileSystem.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,7 @@ extension FileSystem {
900900
}
901901
}
902902

903+
#if !os(Windows)
903904
extension dirent {
904905
/// Get the directory name.
905906
///
@@ -911,4 +912,4 @@ extension dirent {
911912
}
912913
}
913914
}
914-
915+
#endif

swift-tools-support-core/Sources/TSCBasic/Path.swift

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,12 @@ private struct UNIXPath: Path {
421421
return name != "" && name != "." && name != ".." && !name.contains("/")
422422
}
423423

424+
#if os(Windows)
425+
static func isAbsolutePath(_ path: String) -> Bool {
426+
return !path.withCString(encodedAs: UTF16.self, PathIsRelativeW)
427+
}
428+
#endif
429+
424430
var dirname: String {
425431
#if os(Windows)
426432
let dir = string.deletingLastPathComponent
@@ -445,7 +451,11 @@ private struct UNIXPath: Path {
445451
}
446452

447453
var isAbsolute: Bool {
448-
string.hasPrefix("/")
454+
#if os(Windows)
455+
return UNIXPath.isAbsolutePath(string)
456+
#else
457+
return string.hasPrefix("/")
458+
#endif
449459
}
450460

451461
var basename: String {
@@ -632,7 +642,7 @@ private struct UNIXPath: Path {
632642
defer { fsr.deallocate() }
633643

634644
let realpath = String(cString: fsr)
635-
if realpath.withCString(encodedAs: UTF16.self, PathIsRelativeW) {
645+
if !UNIXPath.isAbsolutePath(realpath) {
636646
throw PathValidationError.invalidAbsolutePath(path)
637647
}
638648
self.init(normalizingAbsolutePath: path)
@@ -654,7 +664,7 @@ private struct UNIXPath: Path {
654664
defer { fsr.deallocate() }
655665

656666
let realpath: String = String(cString: fsr)
657-
if !realpath.withCString(encodedAs: UTF16.self, PathIsRelativeW) {
667+
if UNIXPath.isAbsolutePath(realpath) {
658668
throw PathValidationError.invalidRelativePath(path)
659669
}
660670
self.init(normalizingRelativePath: path)

swift-tools-support-core/Sources/TSCBasic/Process.swift

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ public struct ProcessResult: CustomStringConvertible {
3131
public enum ExitStatus: Equatable {
3232
/// The process was terminated normally with a exit code.
3333
case terminated(code: Int32)
34-
34+
#if !os(Windows)
3535
/// The process was terminated due to a signal.
3636
case signalled(signal: Int32)
37+
#endif
3738
}
3839

3940
/// The arguments with which the process was launched.
@@ -177,6 +178,8 @@ public final class Process: ObjectIdentifierProtocol {
177178
/// Typealias for process id type.
178179
#if !os(Windows)
179180
public typealias ProcessID = pid_t
181+
#else
182+
public typealias ProcessID = DWORD
180183
#endif
181184

182185
/// Typealias for stdout/stderr output closure.
@@ -206,6 +209,9 @@ public final class Process: ObjectIdentifierProtocol {
206209
/// The process id of the spawned process, available after the process is launched.
207210
#if os(Windows)
208211
private var _process: Foundation.Process?
212+
public var processID: ProcessID {
213+
return DWORD(_process?.processIdentifier ?? 0)
214+
}
209215
#else
210216
public private(set) var processID = ProcessID()
211217
#endif
@@ -314,7 +320,7 @@ public final class Process: ObjectIdentifierProtocol {
314320
}
315321
// FIXME: This can be cached.
316322
let envSearchPaths = getEnvSearchPaths(
317-
pathString: ProcessEnv.vars["PATH"],
323+
pathString: ProcessEnv.path,
318324
currentWorkingDirectory: localFileSystem.currentWorkingDirectory
319325
)
320326
// Lookup and cache the executable path.
@@ -340,14 +346,15 @@ public final class Process: ObjectIdentifierProtocol {
340346
}
341347

342348
// Look for executable.
343-
guard Process.findExecutable(arguments[0]) != nil else {
344-
throw Process.Error.missingExecutableProgram(program: arguments[0])
349+
let executable = arguments[0]
350+
guard let executablePath = Process.findExecutable(executable) else {
351+
throw Process.Error.missingExecutableProgram(program: executable)
345352
}
346353

347354
#if os(Windows)
348355
_process = Foundation.Process()
349-
_process?.arguments = arguments
350-
_process?.executableURL = URL(fileURLWithPath: arguments[0])
356+
_process?.arguments = Array(arguments.dropFirst()) // Avoid including the executable URL twice.
357+
_process?.executableURL = executablePath.asURL
351358
_process?.environment = environment
352359

353360
if outputRedirection.redirectsOutput {
@@ -752,9 +759,10 @@ extension ProcessResult.Error: CustomStringConvertible {
752759
switch result.exitStatus {
753760
case .terminated(let code):
754761
stream <<< "terminated(\(code)): "
755-
762+
#if !os(Windows)
756763
case .signalled(let signal):
757764
stream <<< "signalled(\(signal)): "
765+
#endif
758766
}
759767

760768
// Strip sandbox information from arguments to keep things pretty.

swift-tools-support-core/Sources/TSCBasic/ProcessEnv.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ public enum ProcessEnv {
5757
invalidateEnv()
5858
}
5959

60+
/// `PATH` variable in the process's environment (`Path` under Windows).
61+
public static var path: String? {
62+
#if os(Windows)
63+
let pathArg = "Path"
64+
#else
65+
let pathArg = "PATH"
66+
#endif
67+
return vars[pathArg]
68+
}
69+
6070
/// The current working directory of the process.
6171
public static var cwd: AbsolutePath? {
6272
return localFileSystem.currentWorkingDirectory

swift-tools-support-core/Sources/TSCBasic/StringConversions.swift

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift.org open source project
33

4-
Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
4+
Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
55
Licensed under Apache License v2.0 with Runtime Library Exception
66

77
See http://swift.org/LICENSE.txt for license information
@@ -15,6 +15,11 @@
1515
///
1616
/// - Returns: True if shell escaping is not needed.
1717
private func inShellWhitelist(_ codeUnit: UInt8) -> Bool {
18+
#if os(Windows)
19+
if codeUnit == UInt8(ascii: "\\") {
20+
return true
21+
}
22+
#endif
1823
switch codeUnit {
1924
case UInt8(ascii: "a")...UInt8(ascii: "z"),
2025
UInt8(ascii: "A")...UInt8(ascii: "Z"),
@@ -38,7 +43,7 @@ private func inShellWhitelist(_ codeUnit: UInt8) -> Bool {
3843
extension String {
3944

4045
/// Creates a shell escaped string. If the string does not need escaping, returns the original string.
41-
/// Otherwise escapes using single quotes. For example:
46+
/// Otherwise escapes using single quotes on Unix and double quotes on Windows. For example:
4247
/// hello -> hello, hello$world -> 'hello$world', input A -> 'input A'
4348
///
4449
/// - Returns: Shell escaped string.
@@ -49,23 +54,30 @@ extension String {
4954
return self
5055
}
5156

52-
// If there are no single quotes then we can just wrap the string around single quotes.
53-
guard let singleQuotePos = utf8[pos...].firstIndex(of: UInt8(ascii: "'")) else {
54-
return "'" + self + "'"
57+
#if os(Windows)
58+
let quoteCharacter: Character = "\""
59+
let escapedQuoteCharacter = "\"\""
60+
#else
61+
let quoteCharacter: Character = "'"
62+
let escapedQuoteCharacter = "'\\''"
63+
#endif
64+
// If there are no quote characters then we can just wrap the string within the quotes.
65+
guard let quotePos = utf8[pos...].firstIndex(of: quoteCharacter.asciiValue!) else {
66+
return String(quoteCharacter) + self + String(quoteCharacter)
5567
}
5668

5769
// Otherwise iterate and escape all the single quotes.
58-
var newString = "'" + String(self[..<singleQuotePos])
70+
var newString = String(quoteCharacter) + String(self[..<quotePos])
5971

60-
for char in self[singleQuotePos...] {
61-
if char == "'" {
62-
newString += "'\\''"
72+
for char in self[quotePos...] {
73+
if char == quoteCharacter {
74+
newString += escapedQuoteCharacter
6375
} else {
6476
newString += String(char)
6577
}
6678
}
6779

68-
newString += "'"
80+
newString += String(quoteCharacter)
6981

7082
return newString
7183
}

swift-tools-support-core/Sources/TSCBasic/TemporaryFile.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,13 @@ public func withTemporaryFile<Result>(
135135
let tempFile = try TemporaryFile(dir: dir, prefix: prefix, suffix: suffix)
136136
defer {
137137
if deleteOnClose {
138+
#if os(Windows)
139+
_ = tempFile.path.pathString.withCString(encodedAs: UTF16.self) {
140+
_wunlink($0)
141+
}
142+
#else
138143
unlink(tempFile.path.pathString)
144+
#endif
139145
}
140146
}
141147
return try body(tempFile)

swift-tools-support-core/Sources/TSCBasic/TerminalController.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,18 +109,30 @@ public final class TerminalController {
109109

110110
/// Computes the terminal type of the stream.
111111
public static func terminalType(_ stream: LocalFileOutputByteStream) -> TerminalType {
112+
#if os(Windows)
113+
return _isatty(_fileno(stream.filePointer)) == 0 ? .file : .tty
114+
#else
112115
if ProcessEnv.vars["TERM"] == "dumb" {
113116
return .dumb
114117
}
115118
let isTTY = isatty(fileno(stream.filePointer)) != 0
116119
return isTTY ? .tty : .file
120+
#endif
117121
}
118122

119123
/// Tries to get the terminal width first using COLUMNS env variable and
120124
/// if that fails ioctl method testing on stdout stream.
121125
///
122126
/// - Returns: Current width of terminal if it was determinable.
123127
public static func terminalWidth() -> Int? {
128+
#if os(Windows)
129+
var csbi: CONSOLE_SCREEN_BUFFER_INFO = CONSOLE_SCREEN_BUFFER_INFO()
130+
if !GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi) {
131+
// GetLastError()
132+
return nil
133+
}
134+
return Int(csbi.srWindow.Right - csbi.srWindow.Left) + 1
135+
#else
124136
// Try to get from environment.
125137
if let columns = ProcessEnv.vars["COLUMNS"], let width = Int(columns) {
126138
return width
@@ -130,13 +142,14 @@ public final class TerminalController {
130142
// Following code does not compile on ppc64le well. TIOCGWINSZ is
131143
// defined in system ioctl.h file which needs to be used. This is
132144
// a temporary arrangement and needs to be fixed.
133-
#if !(arch(powerpc64le) || os(Windows))
145+
#if !arch(powerpc64le)
134146
var ws = winsize()
135147
if ioctl(1, UInt(TIOCGWINSZ), &ws) == 0 {
136148
return Int(ws.ws_col)
137149
}
138150
#endif
139151
return nil
152+
#endif
140153
}
141154

142155
/// Flushes the stream.

0 commit comments

Comments
 (0)