aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/exec/apple/CacheManager.java108
-rw-r--r--src/main/java/com/google/devtools/build/lib/exec/apple/XcodeLocalEnvProvider.java199
-rw-r--r--src/main/java/com/google/devtools/build/lib/remote/RemoteActionContextProvider.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java3
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedSpawnRunner.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextProvider.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/standalone/StandaloneActionContextProvider.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/worker/WorkerActionContextProvider.java2
8 files changed, 122 insertions, 198 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/exec/apple/CacheManager.java b/src/main/java/com/google/devtools/build/lib/exec/apple/CacheManager.java
deleted file mode 100644
index 0c7e52a328..0000000000
--- a/src/main/java/com/google/devtools/build/lib/exec/apple/CacheManager.java
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2016 The Bazel 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.
-
-package com.google.devtools.build.lib.exec.apple;
-
-import com.google.common.base.Joiner;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableList;
-import com.google.devtools.build.lib.vfs.FileSystemUtils;
-import com.google.devtools.build.lib.vfs.Path;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.List;
-import javax.annotation.Nullable;
-
-/**
- * General cache file manager for mapping one or more keys to host-related path information.
- *
- * <p> Cache management has some notable restrictions:
- * <ul>
- * <li>Each cache entry must have the same number of (string) keys, and one value.</li>
- * <li>An entry, once written to the cache, must be stable between builds. Clearing the cache
- * requires a full clean of the bazel output directory.</li>
- * </ul>
- *
- * <p> Note that a single cache manager instance is not thread-safe, though multiple threads may
- * hold cache manager instances for the same cache file. As a result, it is possible multiple
- * threads may write the same entry to cache. This is fine, as retrieval from the cache will simply
- * return the first found entry.
- */
-final class CacheManager {
-
- private final Path cacheFilePath;
- private boolean cacheFileTouched;
-
- /**
- * @param outputRoot path to the bazel's output root
- * @param cacheFilename name of the cache file
- */
- CacheManager(Path outputRoot, String cacheFilename) {
- cacheFilePath = outputRoot.getRelative(cacheFilename);
- }
-
- private void touchCacheFile() throws IOException {
- if (!cacheFileTouched) {
- FileSystemUtils.touchFile(cacheFilePath);
- cacheFileTouched = true;
- }
- }
-
- /**
- * Returns the value associated with the given list of string keys from the cache,
- * or null if the entry is not present in the cache. If there is more than one value for the
- * given key, the first value is returned.
- */
- @Nullable
- public String getValue(String... keys) throws IOException {
- Preconditions.checkArgument(keys.length > 0);
- touchCacheFile();
-
- List<String> keyList = ImmutableList.copyOf(keys);
- Iterable<String> cacheContents =
- FileSystemUtils.readLines(cacheFilePath, StandardCharsets.UTF_8);
- for (String cacheLine : cacheContents) {
- if (cacheLine.isEmpty()) {
- continue;
- }
- List<String> cacheEntry = Splitter.on(':').splitToList(cacheLine);
- List<String> cacheKeys = cacheEntry.subList(0, cacheEntry.size() - 1);
- String cacheValue = cacheEntry.get(cacheEntry.size() - 1);
- if (keyList.size() != cacheKeys.size()) {
- throw new IllegalStateException(
- String.format("cache file %s is malformed. Expected %s keys. line: '%s'",
- cacheFilePath, keyList.size(), cacheLine));
- }
- if (keyList.equals(cacheKeys)) {
- return cacheValue;
- }
- }
- return null;
- }
-
- /**
- * Write an entry to the cache. An entry consists of one or more keys and a single value.
- * No validation is made regarding whether there are redundant or conflicting entries in the
- * cache; it is thus the responsibility of the caller to ensure that any redundant entries
- * (entries which have the same keys) also have the same value.
- */
- public void writeEntry(List<String> keys, String value) throws IOException {
- Preconditions.checkArgument(!keys.isEmpty());
-
- touchCacheFile();
- FileSystemUtils.appendLinesAs(cacheFilePath, StandardCharsets.UTF_8,
- Joiner.on(":").join(ImmutableList.builder().addAll(keys).add(value).build()));
- }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/exec/apple/XcodeLocalEnvProvider.java b/src/main/java/com/google/devtools/build/lib/exec/apple/XcodeLocalEnvProvider.java
index 55a2ba5ddc..a6baec70bb 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/apple/XcodeLocalEnvProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/apple/XcodeLocalEnvProvider.java
@@ -14,10 +14,8 @@
package com.google.devtools.build.lib.exec.apple;
import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
-import com.google.devtools.build.lib.analysis.BlazeDirectories;
import com.google.devtools.build.lib.exec.local.LocalEnvProvider;
import com.google.devtools.build.lib.rules.apple.AppleConfiguration;
import com.google.devtools.build.lib.rules.apple.DottedVersion;
@@ -26,11 +24,14 @@ import com.google.devtools.build.lib.shell.Command;
import com.google.devtools.build.lib.shell.CommandException;
import com.google.devtools.build.lib.shell.CommandResult;
import com.google.devtools.build.lib.shell.TerminationStatus;
-import com.google.devtools.build.lib.util.OS;
import com.google.devtools.build.lib.vfs.Path;
import java.io.IOException;
+import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.logging.Logger;
/**
* Adds to the given environment all variables that are dependent on system state of the host
@@ -44,19 +45,20 @@ import java.util.Map;
* configuration.
*/
public final class XcodeLocalEnvProvider implements LocalEnvProvider {
- private static final String XCRUN_CACHE_FILENAME = "__xcruncache";
- private static final String XCODE_LOCATOR_CACHE_FILENAME = "__xcodelocatorcache";
- private final String productName;
+ private static final Logger log = Logger.getLogger(XcodeLocalEnvProvider.class.getName());
+
private final Map<String, String> clientEnv;
+ private static final ConcurrentMap<String, String> sdkRootCache = new ConcurrentHashMap<>();
+ private static final ConcurrentMap<String, String> developerDirCache = new ConcurrentHashMap<>();
+
/**
* Creates a new {@link XcodeLocalEnvProvider}.
*
* @param clientEnv a map of the current Bazel command's environment
*/
- public XcodeLocalEnvProvider(String productName, Map<String, String> clientEnv) {
- this.productName = productName;
+ public XcodeLocalEnvProvider(Map<String, String> clientEnv) {
this.clientEnv = clientEnv;
}
@@ -89,7 +91,7 @@ public final class XcodeLocalEnvProvider implements LocalEnvProvider {
String developerDir = "";
if (containsXcodeVersion) {
String version = env.get(AppleConfiguration.XCODE_VERSION_ENV_NAME);
- developerDir = getDeveloperDir(execRoot, DottedVersion.fromString(version), productName);
+ developerDir = getDeveloperDir(execRoot, DottedVersion.fromString(version));
newEnvBuilder.put("DEVELOPER_DIR", developerDir);
}
if (containsAppleSdkVersion) {
@@ -99,67 +101,46 @@ public final class XcodeLocalEnvProvider implements LocalEnvProvider {
}
String iosSdkVersion = env.get(AppleConfiguration.APPLE_SDK_VERSION_ENV_NAME);
String appleSdkPlatform = env.get(AppleConfiguration.APPLE_SDK_PLATFORM_ENV_NAME);
- newEnvBuilder.put(
- "SDKROOT",
- getSdkRoot(execRoot, developerDir, iosSdkVersion, appleSdkPlatform, productName));
+ newEnvBuilder.put("SDKROOT", getSdkRoot(developerDir, iosSdkVersion, appleSdkPlatform));
}
return newEnvBuilder.build();
}
/**
- * Returns the absolute root path of the target Apple SDK on the host system for a given version
- * of xcode (as defined by the given {@code developerDir}). This may spawn a process and use the
- * {@code /usr/bin/xcrun} binary to locate the target SDK. This uses a local cache file under
- * {@code bazel-out}, and will only spawn a new {@code xcrun} process in the case of a cache miss.
+ * Queries the path to the target Apple SDK on the host system for a given version of Xcode.
+ *
+ * <p>This spawns a subprocess to run the {@code /usr/bin/xcrun} binary to locate the target SDK.
+ * As this is a costly operation, always call {@link #getSdkRoot(String, String, String)} instead,
+ * which does caching.
*
- * @param execRoot the execution root path, used to locate the cache file
* @param developerDir the value of {@code DEVELOPER_DIR} for the target version of xcode
- * @param sdkVersion the sdk version, for example, "9.1"
- * @param appleSdkPlatform the sdk platform, for example, "iPhoneOS"
- * @param productName the product name
+ * @param sdkVersion the sdk version; for example, {@code 9.1}
+ * @param appleSdkPlatform the sdk platform; for example, {@code iPhoneOS}
+ * @return an absolute path to the root of the target Apple SDK
* @throws IOException if there is an issue with obtaining the root from the spawned process,
* either because the SDK platform/version pair doesn't exist, or there was an unexpected
* issue finding or running the tool
*/
- private static String getSdkRoot(
- Path execRoot,
+ private static String querySdkRoot(
String developerDir,
String sdkVersion,
- String appleSdkPlatform,
- String productName)
+ String appleSdkPlatform)
throws IOException {
- if (OS.getCurrent() != OS.DARWIN) {
- throw new IOException("Cannot locate iOS SDK on non-darwin operating system");
- }
try {
- CacheManager cacheManager =
- new CacheManager(
- execRoot.getRelative(BlazeDirectories.getRelativeOutputPath(productName)),
- XCRUN_CACHE_FILENAME);
-
String sdkString = appleSdkPlatform.toLowerCase() + sdkVersion;
- String cacheResult = cacheManager.getValue(developerDir, sdkString);
- if (cacheResult != null) {
- return cacheResult;
- } else {
- Map<String, String> env =
- Strings.isNullOrEmpty(developerDir)
- ? ImmutableMap.<String, String>of()
- : ImmutableMap.of("DEVELOPER_DIR", developerDir);
- CommandResult xcrunResult =
- new Command(
- new String[] {"/usr/bin/xcrun", "--sdk", sdkString, "--show-sdk-path"},
- env,
- null)
- .execute();
-
- // calling xcrun via Command returns a value with a newline on the end.
- String sdkRoot = new String(xcrunResult.getStdout(), StandardCharsets.UTF_8).trim();
+ Map<String, String> env =
+ Strings.isNullOrEmpty(developerDir)
+ ? ImmutableMap.<String, String>of()
+ : ImmutableMap.of("DEVELOPER_DIR", developerDir);
+ CommandResult xcrunResult =
+ new Command(
+ new String[] {"/usr/bin/xcrun", "--sdk", sdkString, "--show-sdk-path"},
+ env,
+ null)
+ .execute();
- cacheManager.writeEntry(ImmutableList.of(developerDir, sdkString), sdkRoot);
- return sdkRoot;
- }
+ return new String(xcrunResult.getStdout(), StandardCharsets.UTF_8).trim();
} catch (AbnormalTerminationException e) {
TerminationStatus terminationStatus = e.getResult().getTerminationStatus();
@@ -189,47 +170,65 @@ public final class XcodeLocalEnvProvider implements LocalEnvProvider {
}
/**
- * Returns the absolute root path of the xcode developer directory on the host system for the
- * given xcode version. This may spawn a process and use the {@code xcode-locator} binary. This
- * uses a local cache file under {@code bazel-out}, and will only spawn a new process in the case
- * of a cache miss.
+ * Returns the path to the target Apple SDK on the host system for a given version of Xcode.
+ *
+ * <p>This may delegate to {@link #querySdkRoot(String, String, String)} to obtain the path from
+ * external sources in the system. Values are cached in-memory throughout the lifetime of the
+ * Bazel server.
+ *
+ * @param developerDir the value of {@code DEVELOPER_DIR} for the target version of xcode
+ * @param sdkVersion the sdk version; for example, {@code 9.1}
+ * @param appleSdkPlatform the sdk platform; for example, {@code iPhoneOS}
+ * @return an absolute path to the root of the target Apple SDK
+ * @throws IOException if there is an issue with obtaining the root from the spawned process,
+ * either because the SDK platform/version pair doesn't exist, or there was an unexpected
+ * issue finding or running the tool
+ */
+ private static String getSdkRoot(String developerDir, String sdkVersion, String appleSdkPlatform)
+ throws IOException {
+ try {
+ return sdkRootCache.computeIfAbsent(
+ developerDir + ":" + appleSdkPlatform.toLowerCase() + ":" + sdkVersion,
+ (key) -> {
+ try {
+ String sdkRoot = querySdkRoot(developerDir, sdkVersion, appleSdkPlatform);
+ log.info("Queried Xcode SDK root with key " + key + " and got " + sdkRoot);
+ return sdkRoot;
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ });
+ } catch (UncheckedIOException e) {
+ throw e.getCause();
+ }
+ }
+
+ /**
+ * Queries the path to the Xcode developer directory on the host system for the given Xcode
+ * version.
+ *
+ * <p>This spawns a subprocess to run the {@code xcode-locator} binary. As this is a costly
+ * operation, always call {@link #getDeveloperDir(Path, DottedVersion)} instead, which does
+ * caching.
*
* @param execRoot the execution root path, used to locate the cache file
* @param version the xcode version number to look up
- * @param productName the product name
+ * @return an absolute path to the root of the Xcode developer directory
* @throws IOException if there is an issue with obtaining the path from the spawned process,
* either because there is no installed xcode with the given version, or there was an
* unexpected issue finding or running the tool
*/
- private static String getDeveloperDir(Path execRoot, DottedVersion version, String productName)
+ private static String queryDeveloperDir(Path execRoot, DottedVersion version)
throws IOException {
- if (OS.getCurrent() != OS.DARWIN) {
- throw new IOException(
- "Cannot locate xcode developer directory on non-darwin operating system");
- }
try {
- CacheManager cacheManager =
- new CacheManager(
- execRoot.getRelative(BlazeDirectories.getRelativeOutputPath(productName)),
- XCODE_LOCATOR_CACHE_FILENAME);
-
- String cacheResult = cacheManager.getValue(version.toString());
- if (cacheResult != null) {
- return cacheResult;
- } else {
- CommandResult xcodeLocatorResult =
- new Command(
- new String[] {
- execRoot.getRelative("_bin/xcode-locator").getPathString(), version.toString()
- })
- .execute();
-
- String developerDir =
- new String(xcodeLocatorResult.getStdout(), StandardCharsets.UTF_8).trim();
+ CommandResult xcodeLocatorResult =
+ new Command(
+ new String[] {
+ execRoot.getRelative("_bin/xcode-locator").getPathString(), version.toString()
+ })
+ .execute();
- cacheManager.writeEntry(ImmutableList.of(version.toString()), developerDir);
- return developerDir;
- }
+ return new String(xcodeLocatorResult.getStdout(), StandardCharsets.UTF_8).trim();
} catch (AbnormalTerminationException e) {
TerminationStatus terminationStatus = e.getResult().getTerminationStatus();
@@ -258,4 +257,38 @@ public final class XcodeLocalEnvProvider implements LocalEnvProvider {
throw new IOException(e);
}
}
+
+ /**
+ * Returns the absolute root path of the xcode developer directory on the host system for the
+ * given Xcode version.
+ *
+ * <p>This may delegate to {@link #queryDeveloperDir(Path, DottedVersion)} to obtain the path from
+ * external sources in the system. Values are cached in-memory throughout the lifetime of the
+ * Bazel server.
+ *
+ * @param execRoot the execution root path, used to locate the cache file
+ * @param version the xcode version number to look up
+ * @return an absolute path to the root of the Xcode developer directory
+ * @throws IOException if there is an issue with obtaining the path from the spawned process,
+ * either because there is no installed xcode with the given version, or there was an
+ * unexpected issue finding or running the tool
+ */
+ private static String getDeveloperDir(Path execRoot, DottedVersion version)
+ throws IOException {
+ try {
+ return developerDirCache.computeIfAbsent(
+ version.toString(),
+ (key) -> {
+ try {
+ String developerDir = queryDeveloperDir(execRoot, version);
+ log.info("Queried Xcode developer dir with key " + key + " and got " + developerDir);
+ return developerDir;
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ });
+ } catch (UncheckedIOException e) {
+ throw e.getCause();
+ }
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteActionContextProvider.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteActionContextProvider.java
index a4f074a9b9..8877f98572 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteActionContextProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteActionContextProvider.java
@@ -99,7 +99,7 @@ final class RemoteActionContextProvider extends ActionContextProvider {
env.getOptions().getOptions(LocalExecutionOptions.class);
LocalEnvProvider localEnvProvider =
OS.getCurrent() == OS.DARWIN
- ? new XcodeLocalEnvProvider(env.getRuntime().getProductName(), env.getClientEnv())
+ ? new XcodeLocalEnvProvider(env.getClientEnv())
: (OS.getCurrent() == OS.WINDOWS
? new WindowsLocalEnvProvider(env.getClientEnv())
: new PosixLocalEnvProvider(env.getClientEnv()));
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java
index e1e4deb53c..657b5d6e83 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java
@@ -128,8 +128,7 @@ final class DarwinSandboxedSpawnRunner extends AbstractSandboxSpawnRunner {
this.allowNetwork = SandboxHelpers.shouldAllowNetwork(cmdEnv.getOptions());
this.alwaysWritableDirs = getAlwaysWritableDirs(cmdEnv.getRuntime().getFileSystem());
this.processWrapper = ProcessWrapperUtil.getProcessWrapper(cmdEnv);
- this.localEnvProvider =
- new XcodeLocalEnvProvider(cmdEnv.getRuntime().getProductName(), cmdEnv.getClientEnv());
+ this.localEnvProvider = new XcodeLocalEnvProvider(cmdEnv.getClientEnv());
this.sandboxBase = sandboxBase;
this.timeoutKillDelay = timeoutKillDelay;
this.sandboxfsProcess = sandboxfsProcess;
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedSpawnRunner.java
index 629ec0c574..db54f96fdc 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedSpawnRunner.java
@@ -56,7 +56,7 @@ final class ProcessWrapperSandboxedSpawnRunner extends AbstractSandboxSpawnRunne
this.execRoot = cmdEnv.getExecRoot();
this.localEnvProvider =
OS.getCurrent() == OS.DARWIN
- ? new XcodeLocalEnvProvider(productName, cmdEnv.getClientEnv())
+ ? new XcodeLocalEnvProvider(cmdEnv.getClientEnv())
: new PosixLocalEnvProvider(cmdEnv.getClientEnv());
this.sandboxBase = sandboxBase;
this.timeoutKillDelay = timeoutKillDelay;
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextProvider.java b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextProvider.java
index 4e47405d62..d6f847b75c 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextProvider.java
@@ -150,7 +150,7 @@ final class SandboxActionContextProvider extends ActionContextProvider {
env.getOptions().getOptions(LocalExecutionOptions.class);
LocalEnvProvider localEnvProvider =
OS.getCurrent() == OS.DARWIN
- ? new XcodeLocalEnvProvider(env.getRuntime().getProductName(), env.getClientEnv())
+ ? new XcodeLocalEnvProvider(env.getClientEnv())
: new PosixLocalEnvProvider(env.getClientEnv());
return
new LocalSpawnRunner(
diff --git a/src/main/java/com/google/devtools/build/lib/standalone/StandaloneActionContextProvider.java b/src/main/java/com/google/devtools/build/lib/standalone/StandaloneActionContextProvider.java
index 74cab934d1..2b1c6fd7ef 100644
--- a/src/main/java/com/google/devtools/build/lib/standalone/StandaloneActionContextProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/standalone/StandaloneActionContextProvider.java
@@ -72,7 +72,7 @@ public class StandaloneActionContextProvider extends ActionContextProvider {
env.getOptions().getOptions(LocalExecutionOptions.class);
LocalEnvProvider localEnvProvider =
OS.getCurrent() == OS.DARWIN
- ? new XcodeLocalEnvProvider(env.getRuntime().getProductName(), env.getClientEnv())
+ ? new XcodeLocalEnvProvider(env.getClientEnv())
: (OS.getCurrent() == OS.WINDOWS
? new WindowsLocalEnvProvider(env.getClientEnv())
: new PosixLocalEnvProvider(env.getClientEnv()));
diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerActionContextProvider.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerActionContextProvider.java
index 9919568972..f65ee91991 100644
--- a/src/main/java/com/google/devtools/build/lib/worker/WorkerActionContextProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/worker/WorkerActionContextProvider.java
@@ -56,7 +56,7 @@ final class WorkerActionContextProvider extends ActionContextProvider {
env.getOptions().getOptions(LocalExecutionOptions.class);
LocalEnvProvider localEnvProvider =
OS.getCurrent() == OS.DARWIN
- ? new XcodeLocalEnvProvider(env.getRuntime().getProductName(), env.getClientEnv())
+ ? new XcodeLocalEnvProvider(env.getClientEnv())
: (OS.getCurrent() == OS.WINDOWS
? new WindowsLocalEnvProvider(env.getClientEnv())
: new PosixLocalEnvProvider(env.getClientEnv()));