Coverage Report

Created: 2025-11-20 04:52

/root/doris/be/src/util/path_util.cpp
Line
Count
Source (jump to first uncovered line)
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#include "util/path_util.h"
19
20
// Use the POSIX version of dirname(3). See `man 3 dirname`
21
#include <libgen.h>
22
23
#include <cstdlib>
24
#include <filesystem>
25
26
#include "cloud/config.h"
27
#include "common/config.h"
28
#include "gutil/strings/split.h"
29
#include "gutil/strings/strip.h"
30
#include "runtime/plugin/cloud_plugin_downloader.h"
31
32
using std::string;
33
using std::vector;
34
using strings::SkipEmpty;
35
using strings::Split;
36
37
namespace doris {
38
namespace path_util {
39
40
1.20k
std::string join_path_segments(const string& a, const string& b) {
41
1.20k
    if (a.empty()) {
  Branch (41:9): [True: 1, False: 1.20k]
42
1
        return b;
43
1.20k
    } else if (b.empty()) {
  Branch (43:16): [True: 1, False: 1.20k]
44
1
        return a;
45
1.20k
    } else {
46
1.20k
        return StripSuffixString(a, "/") + "/" + StripPrefixString(b, "/");
47
1.20k
    }
48
1.20k
}
49
50
// strdup use malloc to obtain memory for the new string, it should be freed with free.
51
// but std::unique_ptr use delete to free memory by default, so it should specify free memory using free
52
53
21
std::string dir_name(const string& path) {
54
21
    std::vector<char> path_copy(path.c_str(), path.c_str() + path.size() + 1);
55
21
    return dirname(&path_copy[0]);
56
21
}
57
58
54
std::string base_name(const string& path) {
59
54
    std::vector<char> path_copy(path.c_str(), path.c_str() + path.size() + 1);
60
54
    return basename(&path_copy[0]);
61
54
}
62
63
42
std::string file_extension(const string& path) {
64
42
    string file_name = base_name(path);
65
42
    if (file_name == "." || file_name == "..") {
  Branch (65:9): [True: 2, False: 40]
  Branch (65:29): [True: 1, False: 39]
66
3
        return "";
67
3
    }
68
69
39
    string::size_type pos = file_name.rfind(".");
70
39
    return pos == string::npos ? "" : file_name.substr(pos);
  Branch (70:12): [True: 25, False: 14]
71
42
}
72
73
std::string get_real_plugin_url(const std::string& url, const std::string& plugin_dir_config_value,
74
5
                                const std::string& plugin_dir_name, const std::string& doris_home) {
75
5
    if (url.find(":/") == std::string::npos) {
  Branch (75:9): [True: 3, False: 2]
76
3
        return check_and_return_default_plugin_url(url, plugin_dir_config_value, plugin_dir_name,
77
3
                                                   doris_home);
78
3
    }
79
2
    return url;
80
5
}
81
82
std::string check_and_return_default_plugin_url(const std::string& url,
83
                                                const std::string& plugin_dir_config_value,
84
                                                const std::string& plugin_dir_name,
85
7
                                                const std::string& doris_home) {
86
7
    std::string home_dir = doris_home;
87
7
    if (home_dir.empty()) {
  Branch (87:9): [True: 0, False: 7]
88
0
        const char* env_home = std::getenv("DORIS_HOME");
89
0
        if (env_home) {
  Branch (89:13): [True: 0, False: 0]
90
0
            home_dir = std::string(env_home);
91
0
        } else {
92
0
            return "file://" + plugin_dir_config_value + "/" + url;
93
0
        }
94
0
    }
95
96
7
    std::string default_url = home_dir + "/plugins/" + plugin_dir_name;
97
7
    std::string default_old_url = home_dir + "/" + plugin_dir_name;
98
99
7
    if (plugin_dir_config_value == default_url) {
  Branch (99:9): [True: 5, False: 2]
100
        // If true, which means user does not set `jdbc_drivers_dir` and use the default one.
101
        // Because in 2.1.8, we change the default value of `jdbc_drivers_dir`
102
        // from `DORIS_HOME/jdbc_drivers` to `DORIS_HOME/plugins/jdbc_drivers`,
103
        // so we need to check the old default dir for compatibility.
104
5
        std::string target_path = default_url + "/" + url;
105
5
        if (std::filesystem::exists(target_path)) {
  Branch (105:13): [True: 2, False: 3]
106
            // File exists in new default directory
107
2
            return "file://" + target_path;
108
3
        } else if (config::is_cloud_mode()) {
  Branch (108:20): [True: 0, False: 3]
109
            // Cloud mode: try to download from cloud to new default directory
110
0
            CloudPluginDownloader::PluginType plugin_type;
111
0
            if (plugin_dir_name == "jdbc_drivers") {
  Branch (111:17): [True: 0, False: 0]
112
0
                plugin_type = CloudPluginDownloader::PluginType::JDBC_DRIVERS;
113
0
            } else if (plugin_dir_name == "java_udf") {
  Branch (113:24): [True: 0, False: 0]
114
0
                plugin_type = CloudPluginDownloader::PluginType::JAVA_UDF;
115
0
            } else {
116
                // Unknown plugin type, fallback to old directory
117
0
                return "file://" + default_old_url + "/" + url;
118
0
            }
119
120
0
            std::string downloaded_path;
121
0
            Status status = CloudPluginDownloader::download_from_cloud(
122
0
                    plugin_type, url, target_path, &downloaded_path);
123
0
            if (status.ok() && !downloaded_path.empty()) {
  Branch (123:17): [True: 0, False: 0]
  Branch (123:32): [True: 0, False: 0]
124
0
                return "file://" + downloaded_path;
125
0
            }
126
            // Download failed, log warning but continue to fallback
127
0
            LOG(WARNING) << "Failed to download plugin from cloud: " << status.to_string()
128
0
                         << ", fallback to old directory";
129
0
        }
130
131
        // Fallback to old default directory for compatibility
132
3
        return "file://" + default_old_url + "/" + url;
133
5
    } else {
134
        // User specified custom directory - use directly
135
2
        return "file://" + plugin_dir_config_value + "/" + url;
136
2
    }
137
7
}
138
139
} // namespace path_util
140
} // namespace doris