blob: 4d3a5acca60407a9f90dd7bd7e46f33081f80154 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.
#pragma once
#include <filesystem>
#include "common/status.h"
namespace doris {
namespace fs = std::filesystem;
enum class PythonEnvType { CONDA, VENV };
struct PythonVersion {
std::string full_version; // e.g. "3.9.16"
std::string base_path; // e.g. "/root/anaconda3/envs/python3.9"
std::string executable_path; // e.g. "{base_path}/bin/python3"
PythonVersion() = default;
explicit PythonVersion(std::string full_version, std::string base_path,
std::string executable_path)
: full_version(std::move(full_version)),
base_path(std::move(base_path)),
executable_path(std::move(executable_path)) {}
bool operator==(const PythonVersion& other) const {
return full_version == other.full_version && base_path == other.base_path &&
executable_path == other.executable_path;
}
const std::string& get_base_path() const { return base_path; }
const std::string& get_executable_path() const { return executable_path; }
bool is_valid() const {
return !full_version.empty() && !base_path.empty() && !executable_path.empty() &&
fs::exists(base_path) && fs::exists(executable_path);
}
std::string to_string() const {
return fmt::format("[full_version: {}, base_path: {}, executable_path: {}]", full_version,
base_path, executable_path);
}
};
struct PythonEnvironment {
std::string env_name; // e.g. "base" or "myenv"
PythonVersion python_version;
PythonEnvironment(const std::string& name, const PythonVersion& python_version);
std::string to_string() const;
bool is_valid() const;
static Status scan_from_conda_root_path(const fs::path& conda_root_path,
std::vector<PythonEnvironment>* environments);
static Status scan_from_venv_root_path(const fs::path& venv_root_path,
const std::vector<std::string>& interpreter_paths,
std::vector<PythonEnvironment>* environments);
};
class PythonEnvScanner {
public:
PythonEnvScanner(const fs::path& env_root_path) : _env_root_path(env_root_path) {}
virtual ~PythonEnvScanner() = default;
virtual Status scan() = 0;
Status get_versions(std::vector<PythonVersion>* versions) const;
Status get_version(const std::string& runtime_version, PythonVersion* version) const;
std::string root_path() const { return _env_root_path.string(); }
virtual PythonEnvType env_type() const = 0;
virtual std::string to_string() const = 0;
protected:
fs::path _env_root_path;
std::vector<PythonEnvironment> _envs;
};
class CondaEnvScanner : public PythonEnvScanner {
public:
CondaEnvScanner(const fs::path& python_root_path) : PythonEnvScanner(python_root_path) {}
~CondaEnvScanner() override = default;
Status scan() override;
std::string to_string() const override;
PythonEnvType env_type() const override { return PythonEnvType::CONDA; }
};
class VenvEnvScanner : public PythonEnvScanner {
public:
VenvEnvScanner(const fs::path& python_root_path,
const std::vector<std::string>& interpreter_paths)
: PythonEnvScanner(python_root_path), _interpreter_paths(interpreter_paths) {}
~VenvEnvScanner() override = default;
Status scan() override;
std::string to_string() const override;
PythonEnvType env_type() const override { return PythonEnvType::VENV; }
private:
std::vector<std::string> _interpreter_paths;
};
class PythonVersionManager {
public:
static PythonVersionManager& instance() {
static PythonVersionManager instance;
return instance;
}
Status init(PythonEnvType env_type, const fs::path& python_root_path,
const std::string& python_venv_interpreter_paths);
Status get_version(const std::string& runtime_version, PythonVersion* version) const {
return _env_scanner->get_version(runtime_version, version);
}
std::string to_string() const { return _env_scanner->to_string(); }
private:
std::unique_ptr<PythonEnvScanner> _env_scanner;
};
} // namespace doris
namespace std {
template <>
struct hash<doris::PythonVersion> {
size_t operator()(const doris::PythonVersion& v) const noexcept {
return hash<string> {}(v.full_version);
}
};
} // namespace std