python_utils.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/test/python_utils.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base_paths.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/environment.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_path.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/utf_string_conversions.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kPythonPathEnv[] = "PYTHONPATH";
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppendToPythonPath(const FilePath& dir) {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::Environment> env(base::Environment::Create());
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string old_path;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string dir_path;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dir_path = WideToUTF8(dir.value());
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_POSIX)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dir_path = dir.value();
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!env->GetVar(kPythonPathEnv, &old_path)) {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    env->SetVar(kPythonPathEnv, dir_path.c_str());
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (old_path.find(dir_path) == std::string::npos) {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string new_path(old_path);
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_path.append(";");
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_POSIX)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_path.append(":");
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_path.append(dir_path.c_str());
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    env->SetVar(kPythonPathEnv, new_path);
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Search for |to_try|, rolling up the directory tree from
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |start_dir|.  If found, return true and put the path to |to_try| in
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |out_dir|.  If not, return false and leave |out_dir| untouched.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TryRelativeToDir(const FilePath& start_dir,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      const FilePath& to_try,
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      FilePath* out_dir) {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath dir(start_dir);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!file_util::DirectoryExists(dir.Append(to_try))) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FilePath parent = dir.DirName();
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (parent == dir) {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We hit the root directory.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dir = parent;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *out_dir = dir;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetPyProtoPath(FilePath* dir) {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Locate the Python code generated by the protocol buffers compiler.
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath generated_code_dir;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!PathService::Get(base::DIR_EXE, &generated_code_dir)) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Can't find " << generated_code_dir.value();
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const FilePath kPyProto(FILE_PATH_LITERAL("pyproto"));
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath source_dir;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!PathService::Get(base::DIR_SOURCE_ROOT, &source_dir)) {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Can't find " << source_dir.value();
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // On Mac, and possibly Chrome OS, DIR_EXE might be pointing deep
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // into the Release/ (or Debug/) directory and we can't depend on
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // how far down it goes. So we walk upwards from DIR_EXE until we
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // find a likely looking spot.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!TryRelativeToDir(generated_code_dir, kPyProto, dir)) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Can't find " << kPyProto.value()
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << " next to " << generated_code_dir.value();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // On Chrome OS, we may have installed the test binaries and support tools
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // in a wholly separate location, relative to DIR_SOURCE_ROOT.  We'll want
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to do a similar investigation from that point as well.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    generated_code_dir = source_dir
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        .Append(FILE_PATH_LITERAL("out"))
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        .Append(FILE_PATH_LITERAL("Release"));
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!TryRelativeToDir(generated_code_dir, kPyProto, dir)) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(WARNING) << "Can't find " << kPyProto.value()
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << " next to " << generated_code_dir.value();
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  generated_code_dir = *dir;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *dir = generated_code_dir.Append(kPyProto);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(2) << "Found " << kPyProto.value() << " in " << dir->value();
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetPythonCommand(CommandLine* python_cmd) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(python_cmd);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath dir;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!PathService::Get(base::DIR_SOURCE_ROOT, &dir))
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dir = dir.Append(FILE_PATH_LITERAL("third_party"))
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           .Append(FILE_PATH_LITERAL("python_26"))
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           .Append(FILE_PATH_LITERAL("python.exe"));
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_POSIX)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dir = FilePath("python");
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  python_cmd->SetProgram(dir);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Launch python in unbuffered mode, so that python output doesn't mix with
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // gtest output in buildbot log files. See http://crbug.com/147368.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  python_cmd->AppendArg("-u");
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
130