Change --ni-dir option operation
[platform/core/dotnet/launcher.git] / NativeLauncher / tool / dotnettool.cc
1 /*
2  * Copyright (c) 2019 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 "utils.h"
18 #include "ni_common.h"
19 #include "tac_common.h"
20 #include "multi_target_resolver.h"
21 #include "log.h"
22
23 #include <vector>
24 #include <cstring>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <sys/time.h>
28 #include <app_common.h>
29
30 void DisplayUsage() {
31         _SOUT(
32                 "\n"
33                 "Dotnet Tool Version: 1.0\n"
34                 "\n"
35                 "Commands:\n"
36                 "       -h, --help                - Show this help message\n"
37                 "       --ni-system               - Create NI under System DLLs\n"
38                 "       --ni-dll                  - Create NI for DLL\n"
39                 "       --ni-pkg                  - Create NI for package\n"
40                 "                                   (If package is installed under RO area, NI files are generated under RW area)\n"
41                 "       --ni-dir                  - Create NI for directory\n"
42                 "       --ni-reset-system         - Remove System NI files\n"
43                 "       --ni-reset-pkg            - Remove App NI files\n"
44                 "       --ni-reset-dir            - Remove NI for directory\n"
45                 "       --ni-regen-all-app        - Re-generate All App NI files\n"
46                 "       --tac-regen-all           - Re-generate All TAC files\n"
47                 "       --tac-restore-db          - Restore TAC Database\n"
48                 "       --tac-disable-pkg         - Disable TAC for package\n"
49                 "       --tac-enable-pkg          - Enable TAC for package\n"
50                 "       --resolve-all-app         - Remove unused multi-targeting files of all apps\n"
51                 "                                   (this option is used for FOTA script or test)\n"
52                 "       --rm-app-profile          - Remove application profile of given packages for all users\n"
53                 "                                   (this option should be run as root)\n"
54                 "       --rm-all-app-profile      - Remove application profile of all packages for all users\n"
55                 "                                   (this option should be run as root)\n"
56                 "\n"
57                 "Options:\n"
58                 "       --mibc                    - Specify Mibc files. Sepatated with ':'.\n"
59                 "       --verbose                 - Display verbose information\n"
60                 "       --inputbubble             - Compile input assemblies into one bubble with the assemblies described at --inputbubbleref option\n"
61                 "                                   Note!: If you do not have an accurate understanding of Bubble, do not use this option.\n"
62                 "                                          All assemblies in the bubble must be guaranteed to be compiled to the native image before execution.\n"
63                 "                                          If an uncompiled assembly is included in the bubble during execution, an unknown error may occur.\n"
64                 "                                          If --inputbubbleref option doesnot be set, only input files are included to bubble. \n"
65                 "       --inputbubbleref          - Input bubble reference file(s) to be added to bubble (used with --inputbubble option)\n"
66                 "       --ref                     - Reference file(s) for compilation\n"
67                 "                                   (system paths are set automatically.)\n"
68                 "       --no-pipeline             - Compile the dlls individually\n"
69                 "       --print-cmd               - Print command and options\n"
70                 "       --skip-ro-app             - Skip re-generate NI for apps installed RO area\n"
71                 "                                   (This option works with --ni-regen-all-app only)\n"
72                 "\n"
73                 "Usage: dotnettool [options] [command] [arguments]\n"
74                 "\n"
75                 "Example:\n"
76                 "1. Create native image for dlls and exes under platform directories\n"
77                 "   # dotnettool --ni-system\n"
78                 "2. Create native image for dll\n"
79                 "   # dotnettool --ni-dll /usr/bin/Tizen.Runtime.dll\n"
80                 "3. Create native image under the package's bin and lib directory\n"
81                 "   # dotnettool --ni-pkg org.tizen.FormsGallery\n"
82                 "4. Regenerate native images for all installed .net packages\n"
83                 "   # dotnettool --ni-regen-all-app\n"
84                 "5. Create native image for dll based on the Mibc data\n"
85                 "   # dotnettool --mibc /tmp/ibcdata/in.mibc --ni-dll /usr/bin/Tizen.Runtime.dll\n"
86                 "6. Remove profile for package\n"
87                 "   # dotnettool --rm-app-profile org.tizen.FormsGallery\n"
88                 "\n");
89 }
90
91 int main(int argc, char* argv[])
92 {
93         argc--;
94         argv++;
95
96         long starttime;
97         long endtime;
98         struct timeval tv;
99         gettimeofday(&tv, NULL);
100         starttime = tv.tv_sec * 1000l + tv.tv_usec / 1000l;
101
102         if (argc <= 0) {
103                 DisplayUsage();
104                 return -1;
105         }
106
107         NIOption* opt = getNIOption();
108         if (opt == nullptr) {
109                 _SERR("Fail to create option structure.");
110                 return -1;
111         }
112
113         std::vector<std::string> args;
114         for (int i = 0; i < argc; ++i) {
115                 std::string arg = argv[i];
116
117                 if ((arg == "-?") || (arg == "-h") || (arg == "--h")) {
118                         DisplayUsage();
119                         return 0;
120                 } else if (arg == "--verbose") {
121                         opt->flags |= NI_FLAGS_VERBOSE;
122                 } else if (arg == "--inputbubble") {
123                         opt->flags |= NI_FLAGS_INPUT_BUBBLE;
124                 } else if (arg == "--no-pipeline") {
125                         opt->flags |= NI_FLAGS_NO_PIPELINE;
126                 } else if (arg == "--print-cmd") {
127                         opt->flags |= NI_FLAGS_PRINT_CMD;
128                 } else if (arg == "--skip-ro-app") {
129                         opt->flags |= NI_FLAGS_SKIP_RO_APP;
130                 } else if (arg == "--mibc") {
131                         ++i;
132                         if (i >= argc) {
133                                 _SOUT("File path containing Mibc files should be followed for --mibc option");
134                                 DisplayUsage();
135                                 return 0;
136                         }
137
138                         opt->flags |= NI_FLAGS_MIBC;
139
140                         std::vector<std::string> paths;
141                         splitPath(std::string(argv[i]), paths);
142                         for (const auto &path : paths) {
143                                 if (!isFile(path) || isDirectory(path)) {
144                                         _SERR("Mibc file path is missing or does not exist");
145                                         return -1;
146                                 }
147                                 opt->mibcPath.push_back(path);
148                         }
149                 } else if (arg == "--inputbubbleref") {
150                         ++i;
151                         if (i >= argc) {
152                                 _SOUT("Path for references should be followed for --inputbubbleref option");
153                                 DisplayUsage();
154                                 return 0;
155                         }
156
157                         opt->flags |= NI_FLAGS_INPUT_BUBBLE_REF;
158
159                         std::vector<std::string> files;
160                         splitPath(std::string(argv[i]), files);
161                         for (const auto &f : files) {
162                                 opt->inputBubbleRefFiles.push_back(f);
163                         }
164                 } else if (arg == "--ref") {
165                         ++i;
166                         if (i >= argc) {
167                                 _SOUT("Path for references should be followed for --ref option");
168                                 DisplayUsage();
169                                 return 0;
170                         }
171
172                         std::vector<std::string> files;
173                         splitPath(std::string(argv[i]), files);
174                         for (const auto &f : files) {
175                                 opt->refFiles.push_back(f);
176                         }
177                 } else {
178                         args.push_back(arg);
179                 }
180         }
181
182         if (opt->flags & NI_FLAGS_INPUT_BUBBLE_REF && !(opt->flags & NI_FLAGS_INPUT_BUBBLE)) {
183                 _SERR("--inputbubbleref option should be used with --inputbubble option");
184                 DisplayUsage();
185                 return -1;
186         }
187
188         if (initNICommon() != NI_ERROR_NONE) {
189                 return -1;
190         }
191
192         std::vector<std::string>::iterator it = args.begin();
193         std::string cmd = std::string(*it);
194         it = args.erase(it);
195
196         //sh-3.2# dotnettool --ni-system [AssemblyDirectory] [AssemblyDirectory] ...
197         if (cmd == "--ni-system") {
198                 std::string inputs;
199                 while (it != args.end()) {
200                         const std::string dir = std::string(*it);
201                         inputs = inputs + ":" + dir;
202                         it = args.erase(it);
203                 }
204                 int ret = createNIPlatform(inputs, opt);
205                 if (ret != NI_ERROR_NONE) {
206                         _SERR("Failed to generate system NI");
207                 }
208         }
209         //sh-3.2# dotnettool --ni-dll [assemblyPath] [assemblyPath] ...
210         else if (cmd == "--ni-dll") {
211                 if (args.size() < 1) {
212                         _SERR("DLL path is missing");
213                 }
214                 std::vector<std::string> inputs;
215                 while (it != args.end()) {
216                         std::string dll = std::string(*it);
217                         inputs.push_back(dll);
218                         opt->refFiles.push_back(dll);
219                         if (opt->flags & NI_FLAGS_INPUT_BUBBLE) {
220                                 opt->inputBubbleRefFiles.push_back(dll);
221                         }
222                         it = args.erase(it);
223                 }
224
225                 for (auto &dll : inputs) {
226                         int ret = createNIDll(dll, opt);
227                         if (ret != NI_ERROR_NONE && ret != NI_ERROR_ALREADY_EXIST) {
228                                 _SERR("Failed to generate NI file [%s]", dll.c_str());
229                                 break;
230                         }
231                 }
232         }
233         //sh-3.2# dotnettool --ni-pkg [pkgId] [pkgId] ...
234         else if (cmd == "--ni-pkg") {
235                 if (args.size() < 1) {
236                         _SERR("Package name is missing");
237                 }
238                 while (it != args.end()) {
239                         std::string pkg = std::string(*it);
240                         int ret = createNIUnderPkgRoot(pkg, opt);
241                         if (ret != NI_ERROR_NONE) {
242                                 _SERR("Failed to generate app NI [%s]", pkg.c_str());
243                                 break;
244                         }
245                         it = args.erase(it);
246                 }
247         }
248         //sh-3.2# dotnettool --ni-dir [AssemblyDirectory] [AssemblyDirectory] ...
249         else if (cmd == "--ni-dir") {
250                 if (args.size() < 1) {
251                         _SERR("Directory path is missing");
252                 }
253                 std::string dir;
254                 while (it != args.end()) {
255                         if (!dir.empty()) {
256                                 dir += std::string(":");
257                         }
258                         dir += std::string(*it);
259                         it = args.erase(it);
260                 }
261                 if (createNIUnderDirs(dir, opt) != NI_ERROR_NONE) {
262                         _SERR("Failed to generate NI directory");
263                 }
264         }
265         //sh-3.2# dotnettool --ni-reset-system
266         else if (cmd == "--ni-reset-system") {
267                 removeNIPlatform();
268         }
269         //sh-3.2# dotnettool --ni-reset-pkg [pkgId] [pkgId] ...
270         else if (cmd == "--ni-reset-pkg") {
271                 if (args.size() < 1) {
272                         _SERR("Package name is missing");
273                 }
274                 while (it != args.end()) {
275                         std::string pkg = std::string(*it);
276                         int ret = removeNIUnderPkgRoot(pkg);
277                         if (ret != NI_ERROR_NONE) {
278                                 _SERR("Failed to remove dlls for given package [%s]", pkg.c_str());
279                                 break;
280                         }
281                         it = args.erase(it);
282                 }
283         }
284         //sh-3.2# dotnettool --ni-reset-dir [AssemblyDirectory] [AssemblyDirectory] ...
285         else if (cmd == "--ni-reset-dir") {
286                 if (args.size() < 1) {
287                         _SERR("Directory path is missing");
288                 }
289                 while (it != args.end()) {
290                         const std::string dir = std::string(*it);
291                         removeNIUnderDirs(dir);
292                         it = args.erase(it);
293                 }
294         }
295         //sh-3.2# dotnettool --ni-regen-all-app
296         else if (cmd == "--ni-regen-all-app") {
297                 int ret = regenerateAppNI(opt);
298                 if (ret != NI_ERROR_NONE) {
299                         _SERR("Failed to regenerate all app NI");
300                 }
301         }
302         //sh-3.2# dotnettool --tac-regen-all
303         else if (cmd == "--tac-regen-all") {
304                 int ret = regenerateTACNI(opt);
305                 if (ret != NI_ERROR_NONE) {
306                         _SERR("Failed to regenerate all TAC");
307                 }
308         }
309         //sh-3.2# dotnettool --tac-restore-db
310         else if (cmd == "--tac-restore-db") {
311                 int ret = tac_restoreDB();
312                 if (ret != TAC_ERROR_NONE) {
313                         _SERR("Failed to restore TAC db");
314                 }
315                 ret = tlc_restoreDB();
316                 if (ret != TAC_ERROR_NONE) {
317                         _SERR("Failed to restore TLC db");
318                 }
319         }
320         //sh-3.2# dotnettool --tac-enable-pkg [pkgId] [pkgId] ...
321         else if (cmd == "--tac-enable-pkg") {
322                 if (args.size() < 1) {
323                         _SERR("Package name is missing");
324                 }
325                 while (it != args.end()) {
326                         std::string pkg = std::string(*it);
327                         int ret = enableTACPackage(pkg);
328                         if (ret != TAC_ERROR_NONE) {
329                                 _SERR("Failed to enable tac [%s]", pkg.c_str());
330                                 break;
331                         }
332                         it = args.erase(it);
333                 }
334         }
335         //sh-3.2# dotnettool --tac-disable-pkg [pkgId] [pkgId] ...
336         else if (cmd == "--tac-disable-pkg") {
337                 if (args.size() < 1) {
338                         _SERR("Package name is missing");
339                 }
340                 while (it != args.end()) {
341                         std::string pkg = std::string(*it);
342                         int ret = disableTACPackage(pkg);
343                         if (ret != TAC_ERROR_NONE) {
344                                 _SERR("Failed to disable tac [%s]", pkg.c_str());
345                                 break;
346                         }
347                         it = args.erase(it);
348                 }
349         }
350         //sh-3.2# dotnettool --resolve-all-app
351         else if (cmd == "--resolve-all-app") {
352                 int ret = resolveAllApps();
353                 if (ret != 0) {
354                         _SERR("Failed to remove unused multi-targeting files");
355                 }
356         }
357         //sh-3.2# dotnettool --rm-app-profile [pkgId] [pkgId] ...
358         else if (cmd == "--rm-app-profile") {
359                 if (args.size() < 1) {
360                         _SERR("Package name is missing");
361                 }
362                 while (it != args.end()) {
363                         std::string pkg = std::string(*it);
364                         if (removeAppProfileData(pkg) != NI_ERROR_NONE) {
365                                 _SERR("Failed to remove [%s] profile data", pkg.c_str());
366                         }
367                         it = args.erase(it);
368                 }
369         }
370         //sh-3.2# dotnettool --rm-all-app-profile
371         else if (cmd == "--rm-all-app-profile") {
372                 removeAllAppProfileData();
373         }
374         else {
375                 _SERR("Unknown option [%s]", cmd.c_str());
376                 DisplayUsage();
377         }
378
379         finalizeNICommon();
380
381         gettimeofday(&tv, NULL);
382         endtime = tv.tv_sec * 1000l + tv.tv_usec / 1000l;
383         _SOUT("\nSpend time for dotnettool is [%d]ms", (int)(endtime - starttime));
384
385         return 0;
386 }