1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/test/python_utils.h"
6
7#include "base/base_paths.h"
8#include "base/environment.h"
9#include "base/file_path.h"
10#include "base/file_util.h"
11#include "base/logging.h"
12#include "base/memory/scoped_ptr.h"
13#include "base/path_service.h"
14#include "base/utf_string_conversions.h"
15
16const char kPythonPathEnv[] = "PYTHONPATH";
17
18void AppendToPythonPath(const FilePath& dir) {
19  scoped_ptr<base::Environment> env(base::Environment::Create());
20  std::string old_path;
21  std::string dir_path;
22#if defined(OS_WIN)
23  dir_path = WideToUTF8(dir.value());
24#elif defined(OS_POSIX)
25  dir_path = dir.value();
26#endif
27  if (!env->GetVar(kPythonPathEnv, &old_path)) {
28    env->SetVar(kPythonPathEnv, dir_path.c_str());
29  } else if (old_path.find(dir_path) == std::string::npos) {
30    std::string new_path(old_path);
31#if defined(OS_WIN)
32    new_path.append(";");
33#elif defined(OS_POSIX)
34    new_path.append(":");
35#endif
36    new_path.append(dir_path.c_str());
37    env->SetVar(kPythonPathEnv, new_path);
38  }
39}
40
41namespace {
42
43// Search for |to_try|, rolling up the directory tree from
44// |start_dir|.  If found, return true and put the path to |to_try| in
45// |out_dir|.  If not, return false and leave |out_dir| untouched.
46bool TryRelativeToDir(const FilePath& start_dir,
47                      const FilePath& to_try,
48                      FilePath* out_dir) {
49  FilePath dir(start_dir);
50  while (!file_util::DirectoryExists(dir.Append(to_try))) {
51    FilePath parent = dir.DirName();
52    if (parent == dir) {
53      // We hit the root directory.
54      return false;
55    }
56    dir = parent;
57  }
58  *out_dir = dir;
59  return true;
60}
61
62}  // namespace
63
64bool GetPyProtoPath(FilePath* dir) {
65  // Locate the Python code generated by the protocol buffers compiler.
66  FilePath generated_code_dir;
67  if (!PathService::Get(base::DIR_EXE, &generated_code_dir)) {
68    LOG(ERROR) << "Can't find " << generated_code_dir.value();
69    return false;
70  }
71
72  const FilePath kPyProto(FILE_PATH_LITERAL("pyproto"));
73
74#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
75  FilePath source_dir;
76  if (!PathService::Get(base::DIR_SOURCE_ROOT, &source_dir)) {
77    LOG(ERROR) << "Can't find " << source_dir.value();
78    return false;
79  }
80  // On Mac, and possibly Chrome OS, DIR_EXE might be pointing deep
81  // into the Release/ (or Debug/) directory and we can't depend on
82  // how far down it goes. So we walk upwards from DIR_EXE until we
83  // find a likely looking spot.
84  if (!TryRelativeToDir(generated_code_dir, kPyProto, dir)) {
85    LOG(WARNING) << "Can't find " << kPyProto.value()
86                 << " next to " << generated_code_dir.value();
87    // On Chrome OS, we may have installed the test binaries and support tools
88    // in a wholly separate location, relative to DIR_SOURCE_ROOT.  We'll want
89    // to do a similar investigation from that point as well.
90    generated_code_dir = source_dir
91        .Append(FILE_PATH_LITERAL("out"))
92        .Append(FILE_PATH_LITERAL("Release"));
93    if (!TryRelativeToDir(generated_code_dir, kPyProto, dir)) {
94      LOG(WARNING) << "Can't find " << kPyProto.value()
95                   << " next to " << generated_code_dir.value();
96      return false;
97    }
98  }
99  generated_code_dir = *dir;
100#endif
101  *dir = generated_code_dir.Append(kPyProto);
102  VLOG(2) << "Found " << kPyProto.value() << " in " << dir->value();
103  return true;
104}
105
106bool GetPythonRunTime(FilePath* dir) {
107#if defined(OS_WIN)
108  if (!PathService::Get(base::DIR_SOURCE_ROOT, dir))
109    return false;
110  *dir = dir->Append(FILE_PATH_LITERAL("third_party"))
111      .Append(FILE_PATH_LITERAL("python_26"))
112      .Append(FILE_PATH_LITERAL("python.exe"));
113#elif defined(OS_POSIX)
114  *dir = FilePath("python");
115#endif
116  return true;
117}
118