summaryrefslogtreecommitdiff
path: root/platform/platform-api/src/com/intellij/execution/configurations/PathEnvironmentVariableUtil.java
blob: bab90cfcd9b57331deb897e321b37ea1c6b25758 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/*
 * Copyright 2000-2013 JetBrains s.r.o.
 *
 * 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.intellij.execution.configurations;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.EnvironmentUtil;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.FileFilter;
import java.util.Collections;
import java.util.List;

/**
 * @author Sergey Simonchik
 */
public class PathEnvironmentVariableUtil {

  private static final Logger LOG = Logger.getInstance(PathEnvironmentVariableUtil.class);
  private static final String PATH_ENV_VAR_NAME = "PATH";

  private PathEnvironmentVariableUtil() { }

  /**
   * Finds an executable file with the specified base name, that is located in a directory
   * listed in PATH environment variable.
   *
   * @param fileBaseName file base name
   * @return {@code File} instance or null if not found
   */
  @Nullable
  public static File findInPath(@NotNull String fileBaseName) {
    return findInPath(fileBaseName, false);
  }

  /**
   * Finds an executable file with the specified base name, that is located in a directory
   * listed in PATH environment variable and is accepted by filter.
   *
   * @param fileBaseName file base name
   * @param filter exe file filter
   * @return {@code File} instance or null if not found
   */
  @Nullable
  public static File findInPath(@NotNull String fileBaseName, @Nullable FileFilter filter) {
    return findInPath(fileBaseName, false, filter);
  }

  /**
   * Finds an executable file with the specified base name, that is located in a directory
   * listed in PATH environment variable.
   *
   * @param fileBaseName file base name
   * @param  logDetails true if extra logging is needed
   * @return {@code File} instance or null if not found
   */
  @Nullable
  public static File findInPath(@NotNull String fileBaseName, boolean logDetails) {
    return findInPath(fileBaseName, logDetails, null);
  }

  @Nullable
  private static File findInPath(@NotNull String fileBaseName, boolean logDetails, @Nullable FileFilter filter) {
    List<File> exeFiles = findExeFilesInPath(fileBaseName, true, logDetails, filter);
    return exeFiles.size() > 0 ? exeFiles.get(0) : null;
  }

  /**
   * Finds an executable file with the specified base name, that is located in a directory
   * listed in an original PATH environment variable.
   * Original PATH environment variable value is a value returned by <code>System.getenv("PATH")</code>.
   *
   * @param fileBaseName file base name
   * @return {@code File} instance or null if not found
   */
  private static File findInOriginalPath(@NotNull String fileBaseName) {
    String originalPath;
    if (SystemInfo.isMac) {
      originalPath = System.getenv(PATH_ENV_VAR_NAME);
    }
    else {
      originalPath = EnvironmentUtil.getValue(PATH_ENV_VAR_NAME);
    }
    List<File> exeFiles = doFindExeFilesInPath(originalPath, fileBaseName, true, false, null);
    return exeFiles.size() > 0 ? exeFiles.get(0) : null;
  }

  /**
   * Finds all executable files with the specified base name, that are located in directories
   * from PATH environment variable.
   *
   * @param fileBaseName file base name
   * @return file list
   */
  @NotNull
  public static List<File> findAllExeFilesInPath(@NotNull String fileBaseName) {
    return findAllExeFilesInPath(fileBaseName, null);
  }

  @NotNull
  public static List<File> findAllExeFilesInPath(@NotNull String fileBaseName, @Nullable FileFilter filter) {
    return findExeFilesInPath(fileBaseName, false, false, filter);
  }

  @NotNull
  private static List<File> findExeFilesInPath(@NotNull String fileBaseName,
                                               boolean stopAfterFirstMatch,
                                               boolean logDetails,
                                               @Nullable FileFilter filter) {
    String systemPath = EnvironmentUtil.getValue(PATH_ENV_VAR_NAME);
    return doFindExeFilesInPath(systemPath, fileBaseName, stopAfterFirstMatch, logDetails, filter);
  }

  @NotNull
  private static List<File> doFindExeFilesInPath(@Nullable String pathEnvVarValue,
                                                 @NotNull String fileBaseName,
                                                 boolean stopAfterFirstMatch,
                                                 boolean logDetails,
                                                 @Nullable FileFilter filter) {
    if (logDetails) {
      LOG.info("Finding files in PATH (base name=" + fileBaseName + ", PATH=" + StringUtil.notNullize(pathEnvVarValue) + ").");
    }
    if (pathEnvVarValue == null) {
      return Collections.emptyList();
    }
    List<File> result = new SmartList<File>();
    List<String> paths = StringUtil.split(pathEnvVarValue, File.pathSeparator, true, true);
    for (String path : paths) {
      File dir = new File(path);
      if (logDetails) {
        File file = new File(dir, fileBaseName);
        LOG.info("path:" + path + ", path.isAbsolute:" + dir.isAbsolute() + ", path.isDirectory:" + dir.isDirectory()
                 + ", file.isFile:" + file.isFile() + ", file.canExecute:" + file.canExecute());
      }
      if (dir.isAbsolute() && dir.isDirectory()) {
        File exeFile = new File(dir, fileBaseName);
        if (exeFile.isFile() && exeFile.canExecute()) {
          if (filter == null || filter.accept(exeFile)) {
            result.add(exeFile);
            if (stopAfterFirstMatch) {
              return result;
            }
          }
        }
      }
    }
    return result;
  }

  /**
   * Finds the absolute path of an executable file in PATH by the given relative path.
   * This method makes sense for Mac only, because other OSs pass correct environment variables to IDE process
   * letting {@link ProcessBuilder#start} sees correct PATH environment variable.
   *
   * @param exePath String relative path (or just a base name)
   * @return the absolute path if the executable file found, and the given {@code exePath} otherwise
   */
  @NotNull
  public static String findAbsolutePathOnMac(@NotNull String exePath) {
    if (SystemInfo.isMac) {
      if (!exePath.contains(File.separator)) {
        File originalResolvedExeFile = findInOriginalPath(exePath);
        // don't modify exePath if the absolute path can be found in the original PATH
        if (originalResolvedExeFile == null) {
          File resolvedExeFile = findInPath(exePath);
          if (resolvedExeFile != null) {
            exePath = resolvedExeFile.getAbsolutePath();
          }
        }
      }
    }
    return exePath;
  }

}