[Refactoring] Code cleanup and remove duplicate methods
[platform/core/dotnet/launcher.git] / NativeLauncher / tool / multi_target_resolver.cc
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <string>
18 #include <pkgmgr-info.h>
19
20 #include "log.h"
21 #include "utils.h"
22 #include "multi_target_resolver.h"
23
24 static const char* __TIZEN_RID_VERSION_KEY = "db/dotnet/tizen_rid_version"; //8.0.0:7.0.0:6.5.0:6.0.0:5.5.0:5.0.0:4.0.0
25 static const char* __TIZEN_TFM_SUPPORT_KEY = "db/dotnet/tizen_tfm_support"; //net6.0-tizen8.0:net6.0-tizen:net6.0:tizen10.0:tizen90:tizen80:tizen70:tizen60:tizen50:tizen40
26
27 /*
28 Priority | RID                 | TFM
29 ---------|---------------------|-----------------------
30 1        | tizen.X.Y.Z-{arch}  | netX.Y-tizenX.Y ~ 6.5
31 2        | tizen.X.Y.Z         | netX.Y-tizen
32 3        | tizen-{arch}, tizen | netX.Y
33 4        | linux-{arch}, linux | tizen10.0 ~ 40
34 5        | unix-{arch}, unix   | net5.0
35 6        | any                 | netcoreapp3.1 ~ 1.0
36 7        | base                | netstandard2.1 ~ 1.0
37 */
38
39 // Guided by Appfw, vconf daemon does not run at mic stage.
40 // So vconf_get_* api does not work normally.
41 // Therefore, it is changed to manage as a file instead of using vconf API.
42 // /usr/share/dotnet.tizen/lib/dotnet_resolving.info
43 static std::string getDotnetResolvingInfo(const char* key)
44 {
45         std::ifstream ifs(DOTNET_RESOLVING_INFO_PATH);
46         std::string line;
47         while (std::getline(ifs, line)) {
48                 if (!strcmp(line.substr(0, line.find(" ")).c_str(), key)) {
49                         ifs.close();
50                         return line.substr(line.rfind(" ") + 1);
51                 }
52         }
53         return "";
54 }
55
56 static std::vector<std::string> getRidFallbackGraph()
57 {
58         std::string tizen_rid_version = getDotnetResolvingInfo(__TIZEN_RID_VERSION_KEY);
59         std::vector<std::string> rid_version;
60         std::vector<std::string> RID_FALLBACK_GRAPH;
61         splitPath(tizen_rid_version, rid_version);
62         for (auto& ridVersion : rid_version) {
63                 RID_FALLBACK_GRAPH.push_back(std::string("tizen." + ridVersion + "-" + ARCHITECTURE_IDENTIFIER));
64                 RID_FALLBACK_GRAPH.push_back(std::string("tizen." + ridVersion));
65         }
66
67         std::vector<std::string> RID_FALLBACK_OS = {"tizen", "linux", "unix"};
68         for (auto& os : RID_FALLBACK_OS) {
69                 RID_FALLBACK_GRAPH.push_back(std::string(os + "-" + ARCHITECTURE_IDENTIFIER));
70                 RID_FALLBACK_GRAPH.push_back(std::string(os));
71         }
72         RID_FALLBACK_GRAPH.push_back("any");
73         RID_FALLBACK_GRAPH.push_back("base");
74
75         return RID_FALLBACK_GRAPH;
76 }
77
78 static std::vector<std::string> getTfmFallbackGraph()
79 {
80         std::string tizen_tfm_support = getDotnetResolvingInfo(__TIZEN_TFM_SUPPORT_KEY);
81         std::vector<std::string> TFM_FALLBACK_GRAPH;
82         splitPath(tizen_tfm_support, TFM_FALLBACK_GRAPH);
83         TFM_FALLBACK_GRAPH.push_back("net5.0");
84
85         std::vector<std::string> netcoreapp_version = {"3.1", "3.0", "2.2", "2.1", "2.0", "1.1", "1.0"};
86         for (auto& version : netcoreapp_version) {
87                 TFM_FALLBACK_GRAPH.push_back(std::string("netcoreapp" + version));
88         }
89         std::vector<std::string> netstandard_version = {"2.1", "2.0", "1.6", "1.5", "1.4", "1.3", "1.2", "1.1", "1.0"};
90         for (auto& version : netstandard_version) {
91                 TFM_FALLBACK_GRAPH.push_back(std::string("netstandard" + version));
92         }
93
94         return TFM_FALLBACK_GRAPH;
95 }
96
97 // move all files under a certain directory to another directory
98 // ownership / permission / smack label are not changed
99 static bool moveAllFilesTo(const std::string& from, const std::string& to)
100 {
101         std::vector<std::string> files;
102         try {
103                 // make file list to move
104                 for (auto& path : bf::recursive_directory_iterator(from)) {
105                         std::string filePath = path.path().string();
106                         if (isFile(filePath)) {
107                                 files.push_back(filePath);
108                         }
109                 }
110
111                 // move files to target directory
112                 for (auto& f : files) {
113                         bf::rename(f, concatPath(to, getFileName(f)));
114                 }
115         }  catch (const bf::filesystem_error& error) {
116                 _ERR("Failed to iterate directory: %s", error.what());
117                 return false;
118         }
119
120         return true;
121 }
122
123 int resolvePlatformSpecificFiles(const std::string& rootPath)
124 {
125         std::string appBinPath = concatPath(rootPath, "bin");
126         std::string runtimesPath = concatPath(appBinPath, "runtimes");
127
128         // if runtimes directory doesnot exist, return 0
129         if (!isDirectory(runtimesPath)) {
130                 return 0;
131         }
132
133         // found best matched rid and tfm directory and copy all files to bin directory
134         std::vector<std::string> ridFallbackGraph = getRidFallbackGraph();
135         try {
136                 for (auto& rid : bf::recursive_directory_iterator(runtimesPath)) {
137                         std::string ridPath = rid.path().string();
138                         if (bf::is_directory(ridPath) && strstr(ridPath.c_str(), ARCHITECTURE_IDENTIFIER) != NULL) {
139                                 for (auto& ridFG : ridFallbackGraph) {
140                                         if (!strcmp(getFileName(ridPath).c_str(), ridFG.c_str())) {
141                                                 std::string nativePath = concatPath(ridPath, "native");
142                                                 if (isDirectory(nativePath)) {
143                                                         _INFO("Found best matched rid (%s)", ridFG.c_str());
144                                                         // copy all files from bin/runtimes/${rid}/native to appBintPath if exist
145                                                         if (!moveAllFilesTo(nativePath, appBinPath)) {
146                                                                 _ERR("Failed to copy files from native path");
147                                                                 return -1;
148                                                         }
149                                                 }
150
151                                                 // found best matched tfm folder in the found rid folder
152                                                 std::string libPath = concatPath(ridPath, "lib");
153                                                 std::vector<std::string> tfmFallbackGraph = getTfmFallbackGraph();
154                                                 for (auto& tfmFG : tfmFallbackGraph) {
155                                                         std::string tfmPath = concatPath(libPath, tfmFG);
156                                                         if (isDirectory(tfmPath)) {
157                                                                 _INFO("Found best matched tfm (%s)", tfmFG .c_str());
158                                                                 // copy all files from bin/runtimes/${rid}/lib/${tfm} to appBintPath if exist
159                                                                 if (!moveAllFilesTo(tfmPath, appBinPath)) {
160                                                                         _ERR("Failed to copy files from tfm path");
161                                                                         return -1;
162                                                                 }
163                                                                 break;
164                                                         }
165                                                 }
166                                                 break;
167                                         }
168                                 }
169                                 break;
170                         }
171                 }
172         } catch (const bf::filesystem_error& error) {
173                 _ERR("Failed to recursive directory: %s", error.what());
174         }
175
176         // remove runtimes directory
177         if (!removeAll(runtimesPath)) {
178                 _ERR("Failed to remove bin/runtimes directory");
179                 return -1;
180         }
181
182         return 0;
183 }
184
185 // callback function of "pkgmgrinfo_appinfo_filter_foreach_appinfo"
186 static int appResolveCb(pkgmgrinfo_appinfo_h handle, void *user_data)
187 {
188         int ret = 0;
189         char* rootPath;
190
191         ret = pkgmgrinfo_appinfo_get_root_path(handle, &rootPath);
192         if (ret != PMINFO_R_OK) {
193                 _SERR("Failed to get root path");
194                 return -1;
195         }
196
197         if (resolvePlatformSpecificFiles(rootPath) != 0) {
198                 _SERR("Failed to resolve platform specific resources (%s)", rootPath);
199                 return -1;
200         }
201
202         return 0;
203 }
204
205 void resolveAllApps()
206 {
207         int ret = 0;
208
209         pkgmgrinfo_appinfo_filter_h handle;
210         ret = pkgmgrinfo_appinfo_filter_create(&handle);
211         if (ret != PMINFO_R_OK) {
212                 _SERR("Failed to create pkgmgrinfo");
213                 return;
214         }
215
216         ret = pkgmgrinfo_appinfo_filter_add_string(handle, PMINFO_APPINFO_PROP_APP_TYPE, "dotnet");
217         if (ret != PMINFO_R_OK) {
218                 pkgmgrinfo_appinfo_filter_destroy(handle);
219                 _SERR("Failed to add pkgmgrinfo filter app type");
220                 return;
221         }
222
223         ret = pkgmgrinfo_appinfo_filter_foreach_appinfo(handle, appResolveCb, NULL);
224         if (ret != PMINFO_R_OK) {
225                 pkgmgrinfo_appinfo_filter_destroy(handle);
226                 _SERR("Failed to remove unused multi-targeting files");
227                 return;
228         }
229         pkgmgrinfo_appinfo_filter_destroy(handle);
230 }