python_utils.cc revision f2477e01787aa58f445919b809d89e252beef54f
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_util.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.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"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kPythonPathEnv[] = "PYTHONPATH";
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AppendToPythonPath(const base::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)
44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Search for |to_try|, rolling up the directory tree from
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |start_dir|.  If found, return true and put the path to |to_try| in
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |out_dir|.  If not, return false and leave |out_dir| untouched.
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool TryRelativeToDir(const base::FilePath& start_dir,
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      const base::FilePath& to_try,
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      base::FilePath* out_dir) {
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath dir(start_dir);
527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  while (!base::DirectoryExists(dir.Append(to_try))) {
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath parent = dir.DirName();
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (parent == dir) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We hit the root directory.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dir = parent;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *out_dir = dir;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif  // defined(OS_MACOSX) || defined(OS_CHROMEOS)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool GetPyProtoPath(base::FilePath* dir) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Locate the Python code generated by the protocol buffers compiler.
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath generated_code_dir;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!PathService::Get(base::DIR_EXE, &generated_code_dir)) {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Can't find " << generated_code_dir.value();
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const base::FilePath kPyProto(FILE_PATH_LITERAL("pyproto"));
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath source_dir;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!PathService::Get(base::DIR_SOURCE_ROOT, &source_dir)) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Can't find " << source_dir.value();
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // On Mac, and possibly Chrome OS, DIR_EXE might be pointing deep
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // into the Release/ (or Debug/) directory and we can't depend on
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // how far down it goes. So we walk upwards from DIR_EXE until we
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // find a likely looking spot.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!TryRelativeToDir(generated_code_dir, kPyProto, dir)) {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Can't find " << kPyProto.value()
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << " next to " << generated_code_dir.value();
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // On Chrome OS, we may have installed the test binaries and support tools
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // in a wholly separate location, relative to DIR_SOURCE_ROOT.  We'll want
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to do a similar investigation from that point as well.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    generated_code_dir = source_dir
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        .Append(FILE_PATH_LITERAL("out"))
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        .Append(FILE_PATH_LITERAL("Release"));
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!TryRelativeToDir(generated_code_dir, kPyProto, dir)) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(WARNING) << "Can't find " << kPyProto.value()
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << " next to " << generated_code_dir.value();
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  generated_code_dir = *dir;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *dir = generated_code_dir.Append(kPyProto);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(2) << "Found " << kPyProto.value() << " in " << dir->value();
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetPythonCommand(CommandLine* python_cmd) {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(python_cmd);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
112d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  python_cmd->SetProgram(base::FilePath(FILE_PATH_LITERAL("python")));
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Launch python in unbuffered mode, so that python output doesn't mix with
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // gtest output in buildbot log files. See http://crbug.com/147368.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  python_cmd->AppendArg("-u");
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
120