-
Notifications
You must be signed in to change notification settings - Fork 97
Expand file tree
/
Copy pathmain.cpp
More file actions
321 lines (251 loc) · 12.5 KB
/
main.cpp
File metadata and controls
321 lines (251 loc) · 12.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
// system headers
#include <glob.h>
#include <iostream>
// library headers
#include <args.hxx>
// local headers
#include "linuxdeploy/core/appdir.h"
#include "linuxdeploy/core/desktopfile.h"
#include "linuxdeploy/core/elf.h"
#include "linuxdeploy/core/log.h"
#include "linuxdeploy/plugin/plugin.h"
#include "linuxdeploy/util/util.h"
using namespace linuxdeploy::core;
using namespace linuxdeploy::core::log;
using namespace linuxdeploy::util;
namespace bf = boost::filesystem;
int main(int argc, char** argv) {
args::ArgumentParser parser(
"linuxdeploy -- create AppDir bundles with ease"
);
args::HelpFlag help(parser, "help", "Display this help text", {'h', "help"});
args::Flag showVersion(parser, "", "Print version and exit", {'V', "version"});
args::ValueFlag<int> verbosity(parser, "verbosity", "Verbosity of log output (0 = debug, 1 = info (default), 2 = warning, 3 = error)", {'v', "verbosity"});
args::Flag initAppDir(parser, "", "Create basic AppDir structure", {"init-appdir"});
args::ValueFlag<std::string> appDirPath(parser, "appdir", "Path to target AppDir", {"appdir"});
args::ValueFlag<std::string> appName(parser, "app-name", "Application name (used to initialize desktop file and name icons etc.)", {'n', "app-name"});
args::ValueFlagList<std::string> sharedLibraryPaths(parser, "library", "Shared library to deploy", {'l', "lib", "library"});
args::ValueFlagList<std::string> executablePaths(parser, "executable", "Executable to deploy", {'e', "executable"});
args::ValueFlagList<std::string> desktopFilePaths(parser, "desktop file", "Desktop file to deploy", {'d', "desktop-file"});
args::Flag createDesktopFile(parser, "", "Create basic desktop file that is good enough for some tests", {"create-desktop-file"});
args::ValueFlagList<std::string> iconPaths(parser, "icon file", "Icon to deploy", {'i', "icon-file"});
args::ValueFlag<std::string> customAppRunPath(parser, "AppRun path", "Path to custom AppRun script (linuxdeploy will not create a symlink but copy this file instead)", {"custom-apprun"});
args::Flag listPlugins(parser, "", "Search for plugins, print them to stdout and exit", {"list-plugins"});
args::ValueFlagList<std::string> inputPlugins(parser, "name", "Input plugins to run (check whether they are available with --list-plugins)", {'p', "plugin"});
args::ValueFlagList<std::string> outputPlugins(parser, "name", "Output plugins to run (check whether they are available with --list-plugins)", {'o', "output"});
try {
parser.ParseCLI(argc, argv);
} catch (args::Help&) {
std::cerr << parser;
return 0;
} catch (args::ParseError& e) {
std::cerr << e.what() << std::endl;
std::cerr << parser;
return 1;
}
// always show version statement
std::cerr << "linuxdeploy version " << LINUXDEPLOY_VERSION << std::endl;
// set verbosity
if (verbosity) {
ldLog::setVerbosity((LD_LOGLEVEL) verbosity.Get());
}
if (showVersion)
return 0;
auto foundPlugins = linuxdeploy::plugin::findPlugins();
if (listPlugins) {
ldLog() << "Available plugins:" << std::endl;
for (const auto& plugin : foundPlugins) {
ldLog() << plugin.first << LD_NO_SPACE << ":" << plugin.second->path()
<< "(type:" << plugin.second->pluginTypeString() << LD_NO_SPACE << ","
<< "API level:" << plugin.second->apiLevel()
<< LD_NO_SPACE << ")" << std::endl;
}
return 0;
}
if (!appDirPath) {
ldLog() << LD_ERROR << "--appdir parameter required" << std::endl;
std::cerr << std::endl << parser;
return 1;
}
appdir::AppDir appDir(appDirPath.Get());
if (appName) {
ldLog() << std::endl << "-- Deploying application \"" << LD_NO_SPACE << appName.Get() << LD_NO_SPACE << "\" --" << std::endl;
appDir.setAppName(appName.Get());
}
// initialize AppDir with common directories on request
if (initAppDir) {
ldLog() << std::endl << "-- Creating basic AppDir structure --" << std::endl;
if (!appDir.createBasicStructure())
return 1;
}
ldLog() << std::endl << "-- Deploying dependencies for existing files in AppDir --" << std::endl;
if (!appDir.deployDependenciesForExistingFiles()) {
ldLog() << LD_ERROR << "Failed to deploy dependencies for existing files" << std::endl;
return 1;
}
// deploy shared libraries to usr/lib, and deploy their dependencies to usr/lib
if (sharedLibraryPaths) {
ldLog() << std::endl << "-- Deploying shared libraries --" << std::endl;
for (const auto& libraryPath : sharedLibraryPaths.Get()) {
if (!bf::exists(libraryPath)) {
std::cerr << "No such file or directory: " << libraryPath << std::endl;
return 1;
}
if (!appDir.forceDeployLibrary(libraryPath)) {
std::cerr << "Failed to deploy library: " << libraryPath << std::endl;
return 1;
}
}
}
// deploy executables to usr/bin, and deploy their dependencies to usr/lib
if (executablePaths) {
ldLog() << std::endl << "-- Deploying executables --" << std::endl;
for (const auto& executablePath : executablePaths.Get()) {
if (!bf::exists(executablePath)) {
std::cerr << "No such file or directory: " << executablePath << std::endl;
return 1;
}
if (!appDir.deployExecutable(executablePath)) {
std::cerr << "Failed to deploy executable: " << executablePath << std::endl;
return 1;
}
}
}
if (iconPaths) {
ldLog() << std::endl << "-- Deploying icons --" << std::endl;
for (const auto& iconPath : iconPaths.Get()) {
if (!bf::exists(iconPath)) {
std::cerr << "No such file or directory: " << iconPath << std::endl;
return 1;
}
if (!appDir.deployIcon(iconPath)) {
std::cerr << "Failed to deploy icon: " << iconPath << std::endl;
return 1;
}
}
}
if (desktopFilePaths) {
ldLog() << std::endl << "-- Deploying desktop files --" << std::endl;
for (const auto& desktopFilePath : desktopFilePaths.Get()) {
if (!bf::exists(desktopFilePath)) {
std::cerr << "No such file or directory: " << desktopFilePath << std::endl;
return 1;
}
desktopfile::DesktopFile desktopFile(desktopFilePath);
if (!appDir.deployDesktopFile(desktopFile)) {
std::cerr << "Failed to deploy desktop file: " << desktopFilePath << std::endl;
return 1;
}
}
}
// perform deferred copy operations before creating other files here or trying to copy the files to the AppDir root
ldLog() << std::endl << "-- Copying files into AppDir --" << std::endl;
if (!appDir.executeDeferredOperations()) {
return 1;
}
if (createDesktopFile) {
if (!executablePaths) {
ldLog() << LD_ERROR << "--create-desktop-file requires at least one executable to be passed" << std::endl;
return 1;
}
ldLog() << std::endl << "-- Creating desktop file --" << std::endl;
ldLog() << LD_WARNING << "Please beware the created desktop file is of low quality and should be edited or replaced before using it for production releases!" << std::endl;
auto executableName = bf::path(executablePaths.Get().front()).filename().string();
auto desktopFilePath = appDir.path() / "usr/share/applications" / (executableName + ".desktop");
if (bf::exists(desktopFilePath)) {
ldLog() << LD_WARNING << "Working on existing desktop file:" << desktopFilePath << std::endl;
} else {
ldLog() << "Creating new desktop file:" << desktopFilePath << std::endl;
}
desktopfile::DesktopFile desktopFile(desktopFilePath);
if (!desktopFile.addDefaultKeys(executableName)) {
ldLog() << LD_WARNING << "Tried to overwrite existing entries in desktop file:" << desktopFilePath << std::endl;
}
if (!desktopFile.save()) {
ldLog() << LD_ERROR << "Failed to save desktop file:" << desktopFilePath << std::endl;
return 1;
}
}
if (inputPlugins) {
for (const auto& pluginName : inputPlugins.Get()) {
auto it = foundPlugins.find(std::string(pluginName));
if (it == foundPlugins.end()) {
ldLog() << LD_ERROR << "Could not find plugin:" << pluginName;
return 1;
}
auto plugin = it->second;
if (plugin->pluginType() != linuxdeploy::plugin::INPUT_TYPE) {
ldLog() << LD_ERROR << "Plugin" << pluginName << "has wrong type:" << plugin->pluginType() << std::endl;
return 1;
}
ldLog() << std::endl << "-- Running input plugin:" << pluginName << "--" << std::endl;
auto retcode = plugin->run(appDir.path());
if (retcode != 0) {
ldLog() << LD_ERROR << "Failed to run plugin:" << pluginName << std::endl;
ldLog() << LD_DEBUG << "Exited with return code:" << retcode << std::endl;
return 1;
}
}
}
// search for desktop file and deploy it to AppDir root
{
ldLog() << std::endl << "-- Deploying files into AppDir root directory --" << std::endl;
auto deployedDesktopFiles = appDir.deployedDesktopFiles();
desktopfile::DesktopFile desktopFile;
if (deployedDesktopFiles.empty()) {
ldLog() << LD_WARNING << "Could not find desktop file in AppDir, cannot create links for AppRun, desktop file and icon in AppDir root" << std::endl;
} else {
if (!appName.Get().empty()) {
auto desktopFileMatchingName = std::find_if(
deployedDesktopFiles.begin(),
deployedDesktopFiles.end(),
[&appName](const desktopfile::DesktopFile& desktopFile) {
auto fileName = desktopFile.path().filename().string();
return stringStartsWith(fileName, appName.Get()) && stringEndsWith(fileName, ".desktop");
}
);
if (desktopFileMatchingName != deployedDesktopFiles.end()) {
desktopFile = *desktopFileMatchingName;
ldLog() << "Found desktop file matching app name:" << desktopFile.path() << std::endl;
} else {
desktopFile = deployedDesktopFiles[0];
ldLog() << LD_WARNING << "Could not find suitable desktop file for given app name" << appName << LD_NO_SPACE << ", using first desktop file found:" << desktopFile.path() << std::endl;
}
} else {
desktopFile = deployedDesktopFiles[0];
ldLog() << LD_WARNING << "App name not specified, using first desktop file found:" << desktopFile.path() << std::endl;
}
ldLog() << "Deploying desktop file:" << desktopFile.path() << std::endl;
bool rv;
if (customAppRunPath) {
rv = appDir.createLinksInAppDirRoot(desktopFile, customAppRunPath.Get());
} else {
rv = appDir.createLinksInAppDirRoot(desktopFile);
}
if (!rv)
return 1;
}
}
if (outputPlugins) {
for (const auto& pluginName : outputPlugins.Get()) {
auto it = foundPlugins.find(std::string(pluginName));
if (it == foundPlugins.end()) {
ldLog() << LD_ERROR << "Could not find plugin:" << pluginName;
return 1;
}
auto plugin = it->second;
if (plugin->pluginType() != linuxdeploy::plugin::OUTPUT_TYPE) {
ldLog() << LD_ERROR << "Plugin" << pluginName << "has wrong type:" << plugin->pluginType() << std::endl;
return 1;
}
ldLog() << std::endl << "-- Running output plugin:" << pluginName << "--" << std::endl;
auto retcode = plugin->run(appDir.path());
if (retcode != 0) {
ldLog() << LD_ERROR << "Failed to run plugin:" << pluginName << std::endl;
ldLog() << LD_DEBUG << "Exited with return code:" << retcode << std::endl;
return 1;
}
}
}
return 0;
}