Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set up default environment and logger instances #139

Merged
merged 3 commits into from
Dec 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
{
"pins" : [
{
"identity" : "filesystem",
"kind" : "remoteSourceControl",
"location" : "https://github.com/tuist/FileSystem/",
"state" : {
"revision" : "86b34a05c343cd30a72214684984543d346febcf",
"version" : "0.6.23"
}
},
{
"identity" : "mockable",
"kind" : "remoteSourceControl",
Expand Down Expand Up @@ -27,6 +36,78 @@
"version" : "1.5.0"
}
},
{
"identity" : "swift-atomics",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-atomics.git",
"state" : {
"revision" : "cd142fd2f64be2100422d658e7411e39489da985",
"version" : "1.2.0"
}
},
{
"identity" : "swift-collections",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-collections.git",
"state" : {
"revision" : "671108c96644956dddcd89dd59c203dcdb36cec7",
"version" : "1.1.4"
}
},
{
"identity" : "swift-log",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-log",
"state" : {
"revision" : "96a2f8a0fa41e9e09af4585e2724c4e825410b91",
"version" : "1.6.2"
}
},
{
"identity" : "swift-log-file",
"kind" : "remoteSourceControl",
"location" : "https://github.com/crspybits/swift-log-file",
"state" : {
"revision" : "aa94b38bf88c7d9cbc87ceafcdffadaffbc2bffa",
"version" : "0.1.0"
}
},
{
"identity" : "swift-log-oslog",
"kind" : "remoteSourceControl",
"location" : "https://github.com/chrisaljoudi/swift-log-oslog",
"state" : {
"revision" : "176d41d46429e79c806333025b226e0c50a0c602",
"version" : "0.2.2"
}
},
{
"identity" : "swift-log-testing",
"kind" : "remoteSourceControl",
"location" : "https://github.com/neallester/swift-log-testing",
"state" : {
"revision" : "8459cec10d45da4c566aaec9052fa4a1bef3b861",
"version" : "0.0.1"
}
},
{
"identity" : "swift-nio",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio",
"state" : {
"revision" : "dca6594f65308c761a9c409e09fbf35f48d50d34",
"version" : "2.77.0"
}
},
{
"identity" : "swift-service-context",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-service-context",
"state" : {
"revision" : "0c62c5b4601d6c125050b5c3a97f20cce881d32b",
"version" : "1.1.0"
}
},
{
"identity" : "swift-syntax",
"kind" : "remoteSourceControl",
Expand All @@ -36,6 +117,24 @@
"version" : "600.0.1"
}
},
{
"identity" : "swift-system",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-system.git",
"state" : {
"revision" : "c8a44d836fe7913603e246acab7c528c2e780168",
"version" : "1.4.0"
}
},
{
"identity" : "xcglogger",
"kind" : "remoteSourceControl",
"location" : "https://github.com/DaveWoodCom/XCGLogger.git",
"state" : {
"revision" : "4def3c1c772ca90ad5e7bfc8ac437c3b0b4276cf",
"version" : "7.1.5"
}
},
{
"identity" : "xctest-dynamic-overlay",
"kind" : "remoteSourceControl",
Expand All @@ -44,6 +143,15 @@
"revision" : "a3f634d1a409c7979cabc0a71b3f26ffa9fc8af1",
"version" : "1.4.3"
}
},
{
"identity" : "zipfoundation",
"kind" : "remoteSourceControl",
"location" : "https://github.com/weichsel/ZIPFoundation",
"state" : {
"revision" : "02b6abe5f6eef7e3cbd5f247c5cc24e246efcfe0",
"version" : "0.9.19"
}
}
],
"version" : 2
Expand Down
6 changes: 6 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,11 @@ let package = Package(
.package(url: "https://github.com/Kolos65/Mockable", .upToNextMajor(from: "0.2.0")),
.package(url: "https://github.com/apple/swift-argument-parser", .upToNextMajor(from: "1.5.0")),
.package(url: "https://github.com/tuist/path", .upToNextMajor(from: "0.3.8")),
.package(url: "https://github.com/tuist/FileSystem/", .upToNextMajor(from: "0.6.23")),
.package(url: "https://github.com/apple/swift-service-context", .upToNextMajor(from: "1.0.0")),
.package(url: "https://github.com/apple/swift-log", .upToNextMajor(from: "1.6.2")),
.package(url: "https://github.com/chrisaljoudi/swift-log-oslog", .upToNextMajor(from: "0.2.2")),
.package(url: "https://github.com/crspybits/swift-log-file", .upToNextMajor(from: "0.1.0")),
.package(url: "https://github.com/neallester/swift-log-testing", .upToNextMajor(from: "0.0.1")),
]
)
79 changes: 79 additions & 0 deletions Sources/VirtualOSEnvironment/Environment.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import FileSystem
import Foundation
import Path
import VirtualOSEnvironmentInterface

public enum EnvironmentError: Error, Equatable, CustomStringConvertible {
case couldntObtainCacheDirectory
case couldntObtainDataDirectory
case couldntObtainConfigDirectory

public var description: String {
switch self {
case .couldntObtainCacheDirectory:
"We couldn't obtain the cache directory. Make sure either $XDG_CACHE_HOME or $HOME are present in the environment."
case .couldntObtainDataDirectory:
"We couldn't obtain the data directory. Make sure either $XDG_DATA_HOME or $HOME are present in the environment."
case .couldntObtainConfigDirectory:
pepicrft marked this conversation as resolved.
Show resolved Hide resolved
"We couldn't obtain the config directory. Make sure either $XDG_CONFIG_HOME or $HOME are present in the environment."
}
}
}

/// Environment represents the environment variable.
public struct Environment: Environmenting {
/// Environment variables of the environment in which virtualOS is running.
public var variables: [String: String]

/// The current working directory.
public var currentWorkingDirectory: AbsolutePath

/// The cache directory.
public var cacheDirectory: AbsolutePath

/// The data directory.
public var dataDirectory: AbsolutePath

/// The config directory.
public var configDirectory: AbsolutePath

/// It returns the current environment.
/// - Returns: It should not be used directly, but dependency-injected down from the root of the program.
static func current() async throws -> Environment {
let variables = ProcessInfo.processInfo.environment
let fileSystem = FileSystem()
let homeDirectory = try variables["HOME"].map { try AbsolutePath(validating: $0) }

let cacheDirectory = if let xdgCacheHomeDirectory = try variables["XDG_CACHE_HOME"]
.map({ try AbsolutePath(validating: $0) }) ?? homeDirectory?.appending(components: [".cache"])
{
xdgCacheHomeDirectory.appending(component: "virtualOS")
} else {
throw EnvironmentError.couldntObtainCacheDirectory
}

let dataDirectory = if let xdgDataHomeDirectory = try variables["XDG_DATA_HOME"]
.map({ try AbsolutePath(validating: $0) }) ?? homeDirectory?
.appending(components: [".local", "share"])
{
xdgDataHomeDirectory.appending(component: "virtualOS")
} else {
throw EnvironmentError.couldntObtainDataDirectory
}
let configDirectory = if let xdgConfigHomeDirectory = try variables["XDG_CONFIG_HOME"]
.map({ try AbsolutePath(validating: $0) }) ?? homeDirectory?.appending(components: [".config"])
{
xdgConfigHomeDirectory.appending(component: "virtualOS")
} else {
throw EnvironmentError.couldntObtainConfigDirectory
}

return Environment(
variables: variables,
currentWorkingDirectory: try await fileSystem.currentWorkingDirectory(),
cacheDirectory: cacheDirectory,
dataDirectory: dataDirectory,
configDirectory: configDirectory
)
}
}
18 changes: 18 additions & 0 deletions Sources/VirtualOSEnvironmentInterface/Environmenting.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Path

public protocol Environmenting: Sendable {
/// The environment variables.
var variables: [String: String] { get }

/// The current working directory.
var currentWorkingDirectory: AbsolutePath { get }

/// The directory where virtualOS should store cache files.
var cacheDirectory: AbsolutePath { get }

/// The directory where virtualOS should store data files.
var dataDirectory: AbsolutePath { get }

/// The directory where virtualOS should store configuration files.
var configDirectory: AbsolutePath { get }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import ServiceContextModule

enum EnvironmentKey: Sendable, ServiceContextKey {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The EnvironmentKey enum needs to be marked as public to allow external modules to create custom ServiceContext instances. Consider changing to:

public enum EnvironmentKey

Spotted by Graphite Reviewer

Is this helpful? React 👍 or 👎 to let us know.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not necessary because a getter is provided through the extension below.

typealias Value = Environmenting
}

extension ServiceContext {
public internal(set) var environment: Environmenting? {
get {
self[EnvironmentKey.self]
}
set {
self[EnvironmentKey.self] = newValue
}
}
}
35 changes: 35 additions & 0 deletions Sources/VirtualOSLogging/Logger.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import FileLogging
import Foundation
import Logging
import LoggingOSLog
import Path
import ServiceContextModule

enum LoggerKey: ServiceContextKey {
typealias Value = Logger
}

extension ServiceContext {
public internal(set) var logger: Logger? {
get {
self[LoggerKey.self]
}
set {
self[LoggerKey.self] = newValue
}
}
}

extension Logger {
/// Creates an instance of the default logger.
/// - Parameter logFilePath: The file where file logs should be stored.
/// - Returns: An instance of `Logger`.
static func makeDefaultLogger(logFilePath: AbsolutePath) -> Logger {
Logger(label: "dev.tuist.virtualos") { label in
MultiplexLogHandler([
try! FileLogHandler(label: label, localFile: URL(fileURLWithPath: logFilePath.pathString)),
LoggingOSLog(label: label),
])
}
}
}
Empty file.
Empty file.
36 changes: 27 additions & 9 deletions Tuist/ProjectDescriptionHelpers/Module.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ public enum Module: CaseIterable {
case network
case oci
case storage
case environment
case logging

public var targetName: String {
switch self {
Expand All @@ -16,14 +18,16 @@ public enum Module: CaseIterable {
case .network: "VirtualOSNetwork"
case .oci: "VirtualOSOCI"
case .storage: "VirtualOSStorage"
case .environment: "VirtualOSEnvironment"
case .logging: "VirtualOSLogging"
}
}

public var product: Product {
switch self {
case .virtualos:
return .commandLineTool
case .pull, .run, .network, .oci, .storage:
case .pull, .run, .network, .oci, .storage, .environment, .logging:
return .staticLibrary
}
}
Expand All @@ -34,9 +38,9 @@ public enum Module: CaseIterable {

public var interfaceTargetName: String? {
switch self {
case .virtualos:
case .virtualos, .logging:
return nil
case .pull, .run, .network, .oci, .storage:
case .pull, .run, .network, .oci, .storage, .environment:
return "\(targetName)Interface"
}
}
Expand All @@ -60,6 +64,20 @@ public enum Module: CaseIterable {
return [
.external(name: "Path"),
]
case .environment:
return [
.external(name: "Path"),
.external(name: "ServiceContextModule"),
.external(name: "FileSystem"),
]
case .logging:
return [
.external(name: "ServiceContextModule"),
.external(name: "Logging"),
.external(name: "LoggingOSLog"),
.external(name: "FileLogging"),
.external(name: "Path"),
]
}
}

Expand All @@ -79,12 +97,12 @@ public enum Module: CaseIterable {
]
}

var hasTests: Bool {
var testsTargetName: String? {
switch self {
case .virtualos:
return false
case .pull, .run, .oci, .storage, .network:
return true
return nil
case .pull, .run, .oci, .storage, .network, .environment, .logging:
return "\(targetName)Tests"
}
}

Expand Down Expand Up @@ -123,9 +141,9 @@ public enum Module: CaseIterable {
])
))

if hasTests {
if let testsTargetName {
targets.append(.target(
name: "\(targetName)Tests",
name: testsTargetName,
destinations: Set(arrayLiteral: destination),
product: .unitTests,
bundleId: bundleId,
Expand Down
Loading