@signageos/cli 2.7.1 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -6
- package/dist/Applet/Build/appletBuildCommand.js +2 -0
- package/dist/Applet/Generate/appletGenerateCommand.js +5 -1
- package/dist/Applet/Start/appletStartCommand.js +3 -1
- package/dist/Applet/Test/Upload/appletTestRunCommand.js +9 -5
- package/dist/Applet/Test/Upload/appletTestUploadCommand.js +5 -3
- package/dist/Applet/Upload/appletUploadCommand.d.ts +15 -1
- package/dist/Applet/Upload/appletUploadCommand.js +82 -13
- package/dist/Applet/Upload/appletUploadCommandHelper.js +3 -3
- package/dist/Applet/Upload/appletUploadFacade.js +124 -52
- package/dist/Applet/Upload/appletUploadFacadeHelper.d.ts +1 -1
- package/dist/Applet/Upload/appletUploadFacadeHelper.js +3 -3
- package/dist/Applet/appletErrors.d.ts +3 -0
- package/dist/Applet/appletErrors.js +8 -1
- package/dist/Applet/appletFacade.js +9 -0
- package/dist/Applet/appletValidation.d.ts +17 -0
- package/dist/Applet/appletValidation.js +62 -0
- package/dist/Auth/loginCommand.js +30 -4
- package/dist/Command/commandProcessor.js +5 -0
- package/dist/Command/globalArgs.d.ts +21 -0
- package/dist/Command/globalArgs.js +30 -0
- package/dist/CommandLine/progressBarFactory.js +51 -10
- package/dist/CustomScript/Upload/customScriptUploadCommand.js +2 -2
- package/dist/Device/Content/setContentCommand.js +2 -2
- package/dist/Device/deviceFacade.js +8 -0
- package/dist/Emulator/emulatorFacade.js +7 -2
- package/dist/Emulator/emulatorFactory.js +18 -0
- package/dist/Firmware/Upload/firmwareUploadCommand.js +7 -10
- package/dist/Firmware/Upload/firmwareUploadFacade.js +15 -6
- package/dist/Organization/organizationFacade.d.ts +1 -1
- package/dist/Organization/organizationFacade.js +50 -13
- package/dist/Plugin/Upload/pluginUploadCommand.js +2 -1
- package/dist/RunControl/runControlHelper.d.ts +7 -1
- package/dist/RunControl/runControlHelper.js +19 -1
- package/dist/Runner/Upload/runnerUploadCommand.js +2 -1
- package/dist/Timing/List/timingListCommand.js +1 -3
- package/dist/helper.d.ts +19 -0
- package/dist/helper.js +45 -3
- package/dist/parameters.d.ts +0 -1
- package/dist/parameters.js +3 -6
- package/docs/applet/upload/index.md +15 -1
- package/docs/index.md +13 -0
- package/package.json +11 -7
package/README.md
CHANGED
|
@@ -45,12 +45,6 @@ sos autocomplete uninstall
|
|
|
45
45
|
This will remove the completion script and the source line from your shell configuration file.
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
## Test
|
|
49
|
-
```bash
|
|
50
|
-
cp .env.amy .env
|
|
51
|
-
npm test
|
|
52
|
-
```
|
|
53
|
-
|
|
54
48
|
## API reference
|
|
55
49
|
### General
|
|
56
50
|
| Argument | Description | Default value |
|
|
@@ -175,6 +169,18 @@ sos applet start
|
|
|
175
169
|
| --detach *(optional)* | Run the applet HTTP server in the background (detached process) | false |
|
|
176
170
|
| --forward-server-url *(optional)* | Custom forward server URL for `sos device connect` command. | https://forward.signageos.io |
|
|
177
171
|
|
|
172
|
+
##### Local Configuration
|
|
173
|
+
You can create a `sos.config.local.json` file in your applet directory to provide configuration values during local development. This file is automatically loaded when running `sos applet start` and passed to your applet as configuration.
|
|
174
|
+
|
|
175
|
+
```json
|
|
176
|
+
{
|
|
177
|
+
"myConfigKey": "myConfigValue",
|
|
178
|
+
"anotherSetting": true
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
This is useful for testing your applet with different configuration values without having to deploy it to a device.
|
|
183
|
+
|
|
178
184
|
#### Applet Tests Upload
|
|
179
185
|
```bash
|
|
180
186
|
sos applet test upload
|
|
@@ -21,6 +21,7 @@ const dist_1 = require("@signageos/sdk/dist");
|
|
|
21
21
|
const appletFacade_1 = require("../appletFacade");
|
|
22
22
|
const log_1 = require("@signageos/sdk/dist/Console/log");
|
|
23
23
|
const debug_1 = __importDefault(require("debug"));
|
|
24
|
+
const appletValidation_1 = require("../appletValidation");
|
|
24
25
|
const Debug = (0, debug_1.default)('@signageos/cli:Applet:Build:appletBuildCommand');
|
|
25
26
|
exports.OPTION_LIST = [organizationFacade_1.NO_DEFAULT_ORGANIZATION_OPTION, organizationFacade_1.ORGANIZATION_UID_OPTION, appletFacade_1.APPLET_UID_OPTION];
|
|
26
27
|
/**
|
|
@@ -56,6 +57,7 @@ exports.appletBuild = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
56
57
|
run(options) {
|
|
57
58
|
return __awaiter(this, void 0, void 0, function* () {
|
|
58
59
|
const currentDirectory = process.cwd();
|
|
60
|
+
yield (0, appletValidation_1.validateAppletDirectory)(currentDirectory);
|
|
59
61
|
const organizationUid = yield (0, organizationFacade_1.getOrganizationUidOrDefaultOrSelect)(options);
|
|
60
62
|
const organization = yield (0, organizationFacade_1.getOrganization)(organizationUid);
|
|
61
63
|
const restApi = yield (0, helper_1.createOrganizationRestApi)(organization);
|
|
@@ -413,11 +413,15 @@ exports.appletGenerate = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
413
413
|
path: path.join(appletRootDirectory, '.sosignore'),
|
|
414
414
|
content: 'node_modules/\n',
|
|
415
415
|
});
|
|
416
|
+
generateFiles.push({
|
|
417
|
+
path: path.join(appletRootDirectory, 'sos.config.local.json'),
|
|
418
|
+
content: '{}\n',
|
|
419
|
+
});
|
|
416
420
|
// Initialise git repository
|
|
417
421
|
if (git === GitOptions.Yes && gitFound) {
|
|
418
422
|
generateFiles.push({
|
|
419
423
|
path: path.join(appletRootDirectory, '.gitignore'),
|
|
420
|
-
content: 'node_modules/\n
|
|
424
|
+
content: 'node_modules/\n/dist/\nsos.config.local.json',
|
|
421
425
|
});
|
|
422
426
|
yield (0, git_1.initGitRepository)(appletRootDirectory, true).catch((error) => {
|
|
423
427
|
console.error(`Git repository initialization failed: ${error}`);
|
|
@@ -24,6 +24,7 @@ const wait_1 = __importDefault(require("../../Timer/wait"));
|
|
|
24
24
|
const appletServerHelper_1 = require("../appletServerHelper");
|
|
25
25
|
const log_1 = require("@signageos/sdk/dist/Console/log");
|
|
26
26
|
const parameters_1 = require("../../parameters");
|
|
27
|
+
const appletValidation_1 = require("../appletValidation");
|
|
27
28
|
const DEFAULT_PORT = 8090;
|
|
28
29
|
const PORT_OPTION = {
|
|
29
30
|
name: 'port',
|
|
@@ -96,8 +97,9 @@ exports.appletStart = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
96
97
|
var _a, _b;
|
|
97
98
|
const currentDirectory = process.cwd();
|
|
98
99
|
const organizationUid = yield (0, organizationFacade_1.getOrganizationUidOrDefaultOrSelect)(options);
|
|
99
|
-
const entryFileAbsolutePath = yield (0, appletUploadCommandHelper_1.getAppletEntryFileAbsolutePath)(currentDirectory, options);
|
|
100
100
|
const appletPath = yield (0, appletUploadCommandHelper_1.getAppletDirectoryAbsolutePath)(currentDirectory, options);
|
|
101
|
+
yield (0, appletValidation_1.validateAppletDirectory)(appletPath);
|
|
102
|
+
const entryFileAbsolutePath = yield (0, appletUploadCommandHelper_1.getAppletEntryFileAbsolutePath)(currentDirectory, options);
|
|
101
103
|
const entryFileRelativePath = (0, appletUploadCommandHelper_1.getAppletEntryFileRelativePath)(entryFileAbsolutePath, appletPath);
|
|
102
104
|
const emulatorUid = yield (0, emulatorFacade_1.loadEmulatorOrCreateNewAndReturnUid)(organizationUid);
|
|
103
105
|
const dev = (0, dist_1.createDevelopment)({
|
|
@@ -24,6 +24,7 @@ const appletTestRunFacade_1 = require("./appletTestRunFacade");
|
|
|
24
24
|
const wait_1 = __importDefault(require("../../../Timer/wait"));
|
|
25
25
|
const commandDefinition_1 = require("../../../Command/commandDefinition");
|
|
26
26
|
const log_1 = require("@signageos/sdk/dist/Console/log");
|
|
27
|
+
const appletValidation_1 = require("../../appletValidation");
|
|
27
28
|
const OPTION_LIST = [
|
|
28
29
|
organizationFacade_1.NO_DEFAULT_ORGANIZATION_OPTION,
|
|
29
30
|
deviceFacade_1.DEVICE_UID_OPTION,
|
|
@@ -75,7 +76,8 @@ exports.appletTestRun = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
75
76
|
const skipConfirmation = !!options.yes;
|
|
76
77
|
let tests = options.test;
|
|
77
78
|
const currentDirectory = process.cwd();
|
|
78
|
-
|
|
79
|
+
yield (0, appletValidation_1.validateAppletDirectory)(currentDirectory);
|
|
80
|
+
const organizationUid = yield (0, organizationFacade_1.getOrganizationUidOrDefaultOrSelect)(options, skipConfirmation);
|
|
79
81
|
const organization = yield (0, organizationFacade_1.getOrganization)(organizationUid);
|
|
80
82
|
const restApi = yield (0, helper_1.createOrganizationRestApi)(organization);
|
|
81
83
|
const deviceUid = yield (0, deviceFacade_1.getDeviceUid)(restApi, options);
|
|
@@ -88,8 +90,10 @@ exports.appletTestRun = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
88
90
|
if (!tests || tests.length === 0) {
|
|
89
91
|
tests = testSuites.map((testSuite) => testSuite.identifier);
|
|
90
92
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
+
// At this point tests should be defined, but TypeScript doesn't know that
|
|
94
|
+
const testsToRun = tests || [];
|
|
95
|
+
(0, appletTestRunFacade_1.validateTestIdentifiers)(testsToRun, testSuites);
|
|
96
|
+
printRunTests(testsToRun);
|
|
93
97
|
if (!skipConfirmation) {
|
|
94
98
|
const response = yield (0, prompts_1.default)({
|
|
95
99
|
type: 'confirm',
|
|
@@ -104,10 +108,10 @@ exports.appletTestRun = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
104
108
|
const progressBar = (0, progressBarFactory_1.createProgressBar)();
|
|
105
109
|
try {
|
|
106
110
|
progressBar.init({
|
|
107
|
-
size:
|
|
111
|
+
size: testsToRun.length,
|
|
108
112
|
name: RUNNING_TEST_TITLE,
|
|
109
113
|
});
|
|
110
|
-
yield restApi.device.appletTest.run(device.uid, applet.uid, appletVersion.version,
|
|
114
|
+
yield restApi.device.appletTest.run(device.uid, applet.uid, appletVersion.version, testsToRun);
|
|
111
115
|
let deviceAppletTest;
|
|
112
116
|
do {
|
|
113
117
|
yield (0, wait_1.default)(1e3);
|
|
@@ -23,6 +23,7 @@ const progressBarFactory_1 = require("../../../CommandLine/progressBarFactory");
|
|
|
23
23
|
const packageConfig_1 = require("@signageos/sdk/dist/FileSystem/packageConfig");
|
|
24
24
|
const commandDefinition_1 = require("../../../Command/commandDefinition");
|
|
25
25
|
const log_1 = require("@signageos/sdk/dist/Console/log");
|
|
26
|
+
const appletValidation_1 = require("../../appletValidation");
|
|
26
27
|
const OPTION_LIST = [
|
|
27
28
|
organizationFacade_1.NO_DEFAULT_ORGANIZATION_OPTION,
|
|
28
29
|
organizationFacade_1.ORGANIZATION_UID_OPTION,
|
|
@@ -79,7 +80,8 @@ exports.appletTestUpload = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
79
80
|
const isVerbose = !!options.verbose;
|
|
80
81
|
const skipConfirmation = !!options.yes;
|
|
81
82
|
const currentDirectory = process.cwd();
|
|
82
|
-
|
|
83
|
+
yield (0, appletValidation_1.validateAppletDirectory)(currentDirectory);
|
|
84
|
+
const organizationUid = yield (0, organizationFacade_1.getOrganizationUidOrDefaultOrSelect)(options, skipConfirmation);
|
|
83
85
|
const organization = yield (0, organizationFacade_1.getOrganization)(organizationUid);
|
|
84
86
|
const restApi = yield (0, helper_1.createOrganizationRestApi)(organization);
|
|
85
87
|
const version = yield (0, appletFacade_1.getAppletVersion)(currentDirectory);
|
|
@@ -151,8 +153,8 @@ exports.appletTestUpload = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
151
153
|
},
|
|
152
154
|
});
|
|
153
155
|
function displaySuccessMessage(appletName, appletVersion) {
|
|
154
|
-
(0, log_1.log)('info',
|
|
155
|
-
(0, log_1.log)('info', `To run the tests, use command ${chalk_1.default.
|
|
156
|
+
(0, log_1.log)('info', `\nApplet ${chalk_1.default.green(appletName)} version ${chalk_1.default.green(appletVersion)} tests has been uploaded.`);
|
|
157
|
+
(0, log_1.log)('info', `To run the tests, use command ${chalk_1.default.green(`sos applet test run`)}`);
|
|
156
158
|
}
|
|
157
159
|
function printMatchedFiles(testFiles) {
|
|
158
160
|
if (testFiles.length > 0) {
|
|
@@ -56,14 +56,28 @@ export declare const OPTION_LIST: readonly [{
|
|
|
56
56
|
* # Upload with organization override
|
|
57
57
|
* sos applet upload --organization-uid abc123def456
|
|
58
58
|
*
|
|
59
|
-
* # Skip confirmation prompts
|
|
59
|
+
* # Skip confirmation prompts (auto-selects if only 1 org available)
|
|
60
60
|
* sos applet upload --yes
|
|
61
61
|
*
|
|
62
|
+
* # CI/CD: Non-interactive upload with specific organization
|
|
63
|
+
* sos applet upload --yes --organization-uid abc123def456
|
|
64
|
+
*
|
|
62
65
|
* # Verbose output with detailed file information
|
|
63
66
|
* sos applet upload --verbose
|
|
64
67
|
*
|
|
65
68
|
* # Update package.json with new applet UID
|
|
66
69
|
* sos applet upload --update-package-config
|
|
70
|
+
*
|
|
71
|
+
* # Complete CI/CD example
|
|
72
|
+
* sos applet upload --yes --organization-uid abc123def456 --update-package-config
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* **Note for CI/CD and --yes flag:**
|
|
76
|
+
* When using `--yes` with multiple organizations:
|
|
77
|
+
* - If you have only 1 organization: it will be auto-selected
|
|
78
|
+
* - If you have multiple organizations: you MUST specify `--organization-uid`
|
|
79
|
+
* - Alternative: Set a default organization with `sos organization set-default`
|
|
80
|
+
*
|
|
67
81
|
* ```
|
|
68
82
|
*
|
|
69
83
|
* @throws {Error} When package.json is missing or invalid
|
|
@@ -1,4 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
36
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
37
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -15,8 +48,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
48
|
exports.appletUpload = exports.OPTION_LIST = void 0;
|
|
16
49
|
const chalk_1 = __importDefault(require("chalk"));
|
|
17
50
|
const prompts_1 = __importDefault(require("prompts"));
|
|
51
|
+
const path = __importStar(require("path"));
|
|
52
|
+
const fs = __importStar(require("fs-extra"));
|
|
18
53
|
const helper_1 = require("../../helper");
|
|
19
|
-
const parameters_1 = require("../../parameters");
|
|
20
54
|
const organizationFacade_1 = require("../../Organization/organizationFacade");
|
|
21
55
|
const appletFacade_1 = require("../appletFacade");
|
|
22
56
|
const appletUploadFacade_1 = require("./appletUploadFacade");
|
|
@@ -30,6 +64,7 @@ const log_1 = require("@signageos/sdk/dist/Console/log");
|
|
|
30
64
|
const sdk_1 = require("@signageos/sdk");
|
|
31
65
|
const GatewayError_1 = __importDefault(require("@signageos/sdk/dist/RestApi/Error/GatewayError"));
|
|
32
66
|
const NotFoundError_1 = __importDefault(require("@signageos/sdk/dist/RestApi/Error/NotFoundError"));
|
|
67
|
+
const appletValidation_1 = require("../appletValidation");
|
|
33
68
|
exports.OPTION_LIST = [
|
|
34
69
|
appletUploadCommandHelper_1.APPLET_PATH_OPTION,
|
|
35
70
|
appletUploadCommandHelper_1.ENTRY_FILE_PATH_OPTION,
|
|
@@ -77,14 +112,28 @@ exports.OPTION_LIST = [
|
|
|
77
112
|
* # Upload with organization override
|
|
78
113
|
* sos applet upload --organization-uid abc123def456
|
|
79
114
|
*
|
|
80
|
-
* # Skip confirmation prompts
|
|
115
|
+
* # Skip confirmation prompts (auto-selects if only 1 org available)
|
|
81
116
|
* sos applet upload --yes
|
|
82
117
|
*
|
|
118
|
+
* # CI/CD: Non-interactive upload with specific organization
|
|
119
|
+
* sos applet upload --yes --organization-uid abc123def456
|
|
120
|
+
*
|
|
83
121
|
* # Verbose output with detailed file information
|
|
84
122
|
* sos applet upload --verbose
|
|
85
123
|
*
|
|
86
124
|
* # Update package.json with new applet UID
|
|
87
125
|
* sos applet upload --update-package-config
|
|
126
|
+
*
|
|
127
|
+
* # Complete CI/CD example
|
|
128
|
+
* sos applet upload --yes --organization-uid abc123def456 --update-package-config
|
|
129
|
+
* ```
|
|
130
|
+
*
|
|
131
|
+
* **Note for CI/CD and --yes flag:**
|
|
132
|
+
* When using `--yes` with multiple organizations:
|
|
133
|
+
* - If you have only 1 organization: it will be auto-selected
|
|
134
|
+
* - If you have multiple organizations: you MUST specify `--organization-uid`
|
|
135
|
+
* - Alternative: Set a default organization with `sos organization set-default`
|
|
136
|
+
*
|
|
88
137
|
* ```
|
|
89
138
|
*
|
|
90
139
|
* @throws {Error} When package.json is missing or invalid
|
|
@@ -103,25 +152,44 @@ exports.appletUpload = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
103
152
|
run(options) {
|
|
104
153
|
return __awaiter(this, void 0, void 0, function* () {
|
|
105
154
|
const currentDirectory = process.cwd();
|
|
106
|
-
const
|
|
155
|
+
const skipPrompts = options.yes;
|
|
156
|
+
const organizationUid = yield (0, organizationFacade_1.getOrganizationUidOrDefaultOrSelect)(options, skipPrompts);
|
|
107
157
|
const organization = yield (0, organizationFacade_1.getOrganization)(organizationUid);
|
|
108
158
|
const restApi = yield (0, helper_1.createOrganizationRestApi)(organization);
|
|
109
|
-
const { name: appletName, version: appletVersion, frontAppletVersion } = yield (0, appletFacade_1.getApplet)(currentDirectory);
|
|
110
159
|
const appletPathOption = options['applet-path'];
|
|
111
160
|
const appletEntryOption = options['entry-file-path'];
|
|
112
161
|
const updatePackageConfig = options['update-package-config'];
|
|
113
162
|
let appletBinaryFilePath = undefined;
|
|
114
163
|
let appletDirectoryPath = undefined;
|
|
115
164
|
let appletEntryFilePath = undefined;
|
|
116
|
-
|
|
165
|
+
// Determine if this is a single file applet by checking if applet-path points to a file
|
|
166
|
+
let isSingleFileApplet = false;
|
|
167
|
+
if (appletPathOption) {
|
|
168
|
+
const appletPath = path.isAbsolute(appletPathOption) ? appletPathOption : path.join(currentDirectory, appletPathOption);
|
|
169
|
+
if (yield fs.pathExists(appletPath)) {
|
|
170
|
+
const stats = yield fs.stat(appletPath);
|
|
171
|
+
isSingleFileApplet = stats.isFile();
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
// If path doesn't exist, fall back to the original logic
|
|
175
|
+
isSingleFileApplet = !appletEntryOption;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
117
178
|
if (isSingleFileApplet) {
|
|
118
179
|
displaySingleFileAppletDeprecationNote();
|
|
119
180
|
appletBinaryFilePath = yield (0, appletUploadCommandHelper_1.getAppletBinaryFileAbsolutePath)(currentDirectory, options);
|
|
120
181
|
}
|
|
121
182
|
else {
|
|
122
183
|
appletDirectoryPath = yield (0, appletUploadCommandHelper_1.getAppletDirectoryAbsolutePath)(currentDirectory, options);
|
|
123
|
-
|
|
184
|
+
// For multi-file applets, use the applet directory as the base for resolving the entry file
|
|
185
|
+
appletEntryFilePath = yield (0, appletUploadCommandHelper_1.getAppletEntryFileAbsolutePath)(appletDirectoryPath, options);
|
|
124
186
|
}
|
|
187
|
+
// Validate that the applet directory contains a valid applet
|
|
188
|
+
// For multi-file applets, validate the resolved applet directory
|
|
189
|
+
// For single-file applets (deprecated), validate the current directory
|
|
190
|
+
const directoryToValidate = appletDirectoryPath !== null && appletDirectoryPath !== void 0 ? appletDirectoryPath : currentDirectory;
|
|
191
|
+
yield (0, appletValidation_1.validateAppletDirectory)(directoryToValidate);
|
|
192
|
+
const { name: appletName, version: appletVersion, frontAppletVersion } = yield (0, appletFacade_1.getApplet)(directoryToValidate);
|
|
125
193
|
let overrideAppletVersionConfirmed = false;
|
|
126
194
|
let createNewAppletVersionConfirmed = false;
|
|
127
195
|
let appletUid;
|
|
@@ -138,7 +206,10 @@ exports.appletUpload = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
138
206
|
}
|
|
139
207
|
finally {
|
|
140
208
|
if (updatePackageConfig) {
|
|
141
|
-
|
|
209
|
+
// For multi-file applets, save to the applet directory's package.json
|
|
210
|
+
// For single-file applets, save to the current directory's package.json
|
|
211
|
+
const packageConfigDirectory = isSingleFileApplet ? currentDirectory : appletDirectoryPath || currentDirectory;
|
|
212
|
+
yield (0, packageConfig_1.saveToPackage)(packageConfigDirectory, { sos: { appletUid } });
|
|
142
213
|
}
|
|
143
214
|
}
|
|
144
215
|
const applet = yield restApi.applet.get(appletUid);
|
|
@@ -233,7 +304,7 @@ exports.appletUpload = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
233
304
|
progressBar: progressBar,
|
|
234
305
|
});
|
|
235
306
|
}
|
|
236
|
-
displaySuccessMessage(applet.uid, applet.name, appletVersion
|
|
307
|
+
displaySuccessMessage(applet.uid, applet.name, appletVersion);
|
|
237
308
|
}
|
|
238
309
|
else if (createNewAppletVersionConfirmed) {
|
|
239
310
|
if (isSingleFileApplet) {
|
|
@@ -262,7 +333,7 @@ exports.appletUpload = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
262
333
|
progressBar,
|
|
263
334
|
});
|
|
264
335
|
}
|
|
265
|
-
displaySuccessMessage(applet.uid, applet.name, appletVersion
|
|
336
|
+
displaySuccessMessage(applet.uid, applet.name, appletVersion);
|
|
266
337
|
}
|
|
267
338
|
}
|
|
268
339
|
catch (error) {
|
|
@@ -274,10 +345,8 @@ exports.appletUpload = (0, commandDefinition_1.createCommandDefinition)({
|
|
|
274
345
|
});
|
|
275
346
|
},
|
|
276
347
|
});
|
|
277
|
-
function displaySuccessMessage(appletUid, appletName, appletVersion
|
|
278
|
-
(0, log_1.log)('info',
|
|
279
|
-
const appletBoxUri = `https://${boxHost}/applet/${appletUid}/${appletVersion}/build`;
|
|
280
|
-
(0, log_1.log)('info', `To build specific applications (Tizen, WebOS, SSSP, BrightSign, RPi, Android etc.) go to ${chalk_1.default.blue(appletBoxUri)}`);
|
|
348
|
+
function displaySuccessMessage(appletUid, appletName, appletVersion) {
|
|
349
|
+
(0, log_1.log)('info', `\nApplet ${chalk_1.default.green(appletName)} version ${chalk_1.default.green(appletVersion)} (${chalk_1.default.blue(appletUid)}) uploaded successfully.`);
|
|
281
350
|
}
|
|
282
351
|
function displaySingleFileAppletDeprecationNote() {
|
|
283
352
|
(0, log_1.log)('warning', `${chalk_1.default.red(`Applets with only applet-path file are ${chalk_1.default.bold(`deprecated`)}.`)} Please find more information at our website.`);
|
|
@@ -82,7 +82,7 @@ function getAppletDirectoryAbsolutePath(currentDirectory, options) {
|
|
|
82
82
|
if (appletDirectoryPath.length > 1 && (appletDirectoryPath.endsWith('/') || appletDirectoryPath.endsWith('\\'))) {
|
|
83
83
|
appletDirectoryPath = appletDirectoryPath.slice(0, -1);
|
|
84
84
|
}
|
|
85
|
-
(0, log_1.log)('info',
|
|
85
|
+
(0, log_1.log)('info', chalk_1.default.white(`Use applet project directory path: ${appletDirectoryPath}`) + '\n');
|
|
86
86
|
const appletDirectoryPathExists = yield fs.pathExists(appletDirectoryPath);
|
|
87
87
|
if (!appletDirectoryPathExists) {
|
|
88
88
|
throw new Error(`Applet project directory not found: ${appletDirectoryPath}`);
|
|
@@ -105,7 +105,7 @@ function getAppletBinaryFileAbsolutePath(currentDirectory, options) {
|
|
|
105
105
|
}
|
|
106
106
|
// Normalize the path for cross-platform compatibility
|
|
107
107
|
appletBinaryFilePath = path.normalize(appletBinaryFilePath);
|
|
108
|
-
(0, log_1.log)('info',
|
|
108
|
+
(0, log_1.log)('info', chalk_1.default.white(`Use applet binary file: ${appletBinaryFilePath}` + '\n'));
|
|
109
109
|
const appletBinaryFilePathExists = yield fs.pathExists(appletBinaryFilePath);
|
|
110
110
|
if (!appletBinaryFilePathExists) {
|
|
111
111
|
throw new Error(`Applet binary file not found: ${appletBinaryFilePath}`);
|
|
@@ -132,7 +132,7 @@ function getAppletEntryFileAbsolutePath(currentDirectory, options) {
|
|
|
132
132
|
}
|
|
133
133
|
// Normalize the path for cross-platform compatibility
|
|
134
134
|
appletEntryFilePath = path.normalize(appletEntryFilePath);
|
|
135
|
-
(0, log_1.log)('info',
|
|
135
|
+
(0, log_1.log)('info', chalk_1.default.white(`Use applet entry file: ${appletEntryFilePath}`) + '\n');
|
|
136
136
|
const appletEntryFilePathExists = yield fs.pathExists(appletEntryFilePath);
|
|
137
137
|
if (!appletEntryFilePathExists) {
|
|
138
138
|
throw new Error(`Applet entry file not found: ${appletEntryFilePath}\nDid you forget to build your applet by ${chalk_1.default.green('sos applet build')}?`);
|
|
@@ -60,9 +60,17 @@ function updateSingleFileApplet(parameters) {
|
|
|
60
60
|
return __awaiter(this, void 0, void 0, function* () {
|
|
61
61
|
const { restApi, applet } = parameters;
|
|
62
62
|
const appletBinary = fs.createReadStream(applet.binaryFilePath, { encoding: 'utf8' });
|
|
63
|
-
yield restApi.applet.version
|
|
63
|
+
yield restApi.applet.version
|
|
64
|
+
.update(applet.uid, applet.version, {
|
|
64
65
|
binary: appletBinary,
|
|
65
66
|
frontAppletVersion: applet.frontAppletVersion,
|
|
67
|
+
})
|
|
68
|
+
.catch((error) => {
|
|
69
|
+
if (error instanceof Error) {
|
|
70
|
+
throw new Error(`Failed to update applet version "${applet.version}" with binary file "${applet.binaryFilePath}": ${error.message}\n` +
|
|
71
|
+
`Please check that the file exists, is readable, and that you have permissions to update the applet.`);
|
|
72
|
+
}
|
|
73
|
+
throw error;
|
|
66
74
|
});
|
|
67
75
|
});
|
|
68
76
|
}
|
|
@@ -91,40 +99,44 @@ const updateMultiFileApplet = (parameters) => __awaiter(void 0, void 0, void 0,
|
|
|
91
99
|
}
|
|
92
100
|
else {
|
|
93
101
|
changedFilesCounter++;
|
|
94
|
-
(0, log_1.log)('info', chalk_1.default.yellow(` Uploading ${fileAbsolutePath}`));
|
|
95
102
|
}
|
|
96
103
|
if (progressBar) {
|
|
97
|
-
progressBar.init({ size: fileSize, name:
|
|
104
|
+
progressBar.init({ size: fileSize, name: fileRelativePosixPath });
|
|
98
105
|
}
|
|
99
106
|
const fileStream = fs.createReadStream(fileAbsolutePath);
|
|
100
107
|
fileStream.pause();
|
|
101
108
|
fileStream.on('data', (chunk) => {
|
|
102
109
|
if (progressBar) {
|
|
103
|
-
progressBar.update({ add: chunk.length });
|
|
110
|
+
progressBar.update({ add: chunk.length, name: fileRelativePosixPath });
|
|
104
111
|
}
|
|
105
112
|
});
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
catch (error) {
|
|
113
|
+
// update file is just alias to create file (both are idempotent)
|
|
114
|
+
yield restApi.applet.version.file
|
|
115
|
+
.update(applet.uid, applet.version, fileRelativePosixPath, {
|
|
116
|
+
content: fileStream,
|
|
117
|
+
hash: fileHash,
|
|
118
|
+
size: fileSize,
|
|
119
|
+
type: fileType,
|
|
120
|
+
}, { build: false })
|
|
121
|
+
.catch((error) => {
|
|
116
122
|
if (fileSize === 0) {
|
|
117
123
|
throw new Error(`Empty files are temporarily disallowed ${fileAbsolutePath}`);
|
|
118
124
|
}
|
|
125
|
+
// Enhance error message with more context
|
|
126
|
+
if (error instanceof Error) {
|
|
127
|
+
const enhancedError = new Error(`Failed to upload file "${fileAbsolutePath}": ${error.message}\n` + `File details: Size=${fileSize} bytes, Type=${fileType}`);
|
|
128
|
+
// Preserve the original stack trace if available
|
|
129
|
+
if (error.stack) {
|
|
130
|
+
enhancedError.stack = error.stack;
|
|
131
|
+
}
|
|
132
|
+
throw enhancedError;
|
|
133
|
+
}
|
|
119
134
|
throw error;
|
|
120
|
-
}
|
|
135
|
+
});
|
|
121
136
|
}
|
|
122
137
|
for (const fileRelativePath in currentAppletFiles) {
|
|
123
138
|
if (Object.prototype.hasOwnProperty.call(currentAppletFiles, fileRelativePath)) {
|
|
124
|
-
|
|
125
|
-
yield restApi.applet.version.file.remove(applet.uid, applet.version, fileRelativePath, { build: false });
|
|
126
|
-
}
|
|
127
|
-
catch (error) {
|
|
139
|
+
yield restApi.applet.version.file.remove(applet.uid, applet.version, fileRelativePath, { build: false }).catch((error) => {
|
|
128
140
|
if (error instanceof NotFoundError_1.default) {
|
|
129
141
|
/*
|
|
130
142
|
* This means that the file we are trying to remove somehow already got removed.
|
|
@@ -134,9 +146,17 @@ const updateMultiFileApplet = (parameters) => __awaiter(void 0, void 0, void 0,
|
|
|
134
146
|
Debug(`remove old file ${fileRelativePath} failed`);
|
|
135
147
|
}
|
|
136
148
|
else {
|
|
149
|
+
// Add more context to file removal errors
|
|
150
|
+
if (error instanceof Error) {
|
|
151
|
+
const enhancedError = new Error(`Failed to remove obsolete file "${fileRelativePath}": ${error.message}`);
|
|
152
|
+
if (error.stack) {
|
|
153
|
+
enhancedError.stack = error.stack;
|
|
154
|
+
}
|
|
155
|
+
throw enhancedError;
|
|
156
|
+
}
|
|
137
157
|
throw error;
|
|
138
158
|
}
|
|
139
|
-
}
|
|
159
|
+
});
|
|
140
160
|
changedFilesCounter++;
|
|
141
161
|
}
|
|
142
162
|
}
|
|
@@ -144,8 +164,16 @@ const updateMultiFileApplet = (parameters) => __awaiter(void 0, void 0, void 0,
|
|
|
144
164
|
const appletEntryFilePosixPath = path.posix.normalize(applet.entryFilePath.replace(/\\/g, '/'));
|
|
145
165
|
if (changedFilesCounter > 0 || appletVersion.entryFile !== appletEntryFilePosixPath) {
|
|
146
166
|
// The update applet version has to be the last after upload all files to trigger applet version build
|
|
147
|
-
yield restApi.applet.version
|
|
167
|
+
yield restApi.applet.version
|
|
168
|
+
.update(applet.uid, applet.version, {
|
|
148
169
|
entryFile: appletEntryFilePosixPath,
|
|
170
|
+
})
|
|
171
|
+
.catch((error) => {
|
|
172
|
+
if (error instanceof Error) {
|
|
173
|
+
throw new Error(`Failed to update applet version with entry file "${appletEntryFilePosixPath}": ${error.message}\n` +
|
|
174
|
+
`This usually happens when the entry file is missing, has errors, or the applet version cannot be built.`);
|
|
175
|
+
}
|
|
176
|
+
throw error;
|
|
149
177
|
});
|
|
150
178
|
}
|
|
151
179
|
if (progressBar) {
|
|
@@ -159,10 +187,18 @@ exports.updateMultiFileApplet = updateMultiFileApplet;
|
|
|
159
187
|
const createSingleFileApplet = (parameters) => __awaiter(void 0, void 0, void 0, function* () {
|
|
160
188
|
const { restApi, applet } = parameters;
|
|
161
189
|
const appletBinary = fs.createReadStream(applet.binaryFilePath, { encoding: 'utf8' });
|
|
162
|
-
yield restApi.applet.version
|
|
190
|
+
yield restApi.applet.version
|
|
191
|
+
.create(applet.uid, {
|
|
163
192
|
binary: appletBinary,
|
|
164
193
|
version: applet.version,
|
|
165
194
|
frontAppletVersion: applet.frontAppletVersion,
|
|
195
|
+
})
|
|
196
|
+
.catch((error) => {
|
|
197
|
+
if (error instanceof Error) {
|
|
198
|
+
throw new Error(`Failed to create applet version "${applet.version}" with binary file "${applet.binaryFilePath}": ${error.message}\n` +
|
|
199
|
+
`Please check that the file exists, is readable, and that you have permissions to create applet versions.`);
|
|
200
|
+
}
|
|
201
|
+
throw error;
|
|
166
202
|
});
|
|
167
203
|
});
|
|
168
204
|
exports.createSingleFileApplet = createSingleFileApplet;
|
|
@@ -170,39 +206,71 @@ const createMultiFileFileApplet = (parameters) => __awaiter(void 0, void 0, void
|
|
|
170
206
|
const { restApi, applet, progressBar } = parameters;
|
|
171
207
|
const appletEntryFilePosixPath = path.posix.normalize(applet.entryFilePath.replace(/\\/g, '/'));
|
|
172
208
|
try {
|
|
173
|
-
yield restApi.applet.version
|
|
209
|
+
yield restApi.applet.version
|
|
210
|
+
.create(applet.uid, {
|
|
174
211
|
version: applet.version,
|
|
175
212
|
entryFile: appletEntryFilePosixPath,
|
|
176
|
-
})
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const fileSize = (yield fs.stat(fileAbsolutePath)).size;
|
|
182
|
-
if (fileSize === 0) {
|
|
183
|
-
throw new Error(`Empty files are temporarily disallowed ${fileAbsolutePath}`);
|
|
184
|
-
}
|
|
185
|
-
if (progressBar) {
|
|
186
|
-
progressBar.init({ size: fileSize, name: fileRelativePath });
|
|
213
|
+
})
|
|
214
|
+
.catch((error) => {
|
|
215
|
+
if (error instanceof Error) {
|
|
216
|
+
throw new Error(`Failed to create applet version "${applet.version}": ${error.message}\n` +
|
|
217
|
+
`Please check that you have permissions to create applet versions and that the version is valid.`);
|
|
187
218
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
219
|
+
throw error;
|
|
220
|
+
});
|
|
221
|
+
// Process files sequentially to avoid concurrent progress bar issues
|
|
222
|
+
for (const fileAbsolutePath of applet.files) {
|
|
223
|
+
try {
|
|
224
|
+
const fileRelativePath = (0, appletUploadFacadeHelper_1.getAppletFileRelativePath)(fileAbsolutePath, applet.directoryPath);
|
|
225
|
+
const fileHash = yield (0, fileSystem_1.getFileMD5Checksum)(fileAbsolutePath);
|
|
226
|
+
const fileType = yield (0, fileSystem_1.getFileType)(fileAbsolutePath);
|
|
227
|
+
const fileSize = (yield fs.stat(fileAbsolutePath)).size;
|
|
228
|
+
if (fileSize === 0) {
|
|
229
|
+
(0, log_1.log)('info', chalk_1.default.yellow(`Skipping empty file ${fileAbsolutePath}`));
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
const filePosixPath = path.posix.normalize(fileRelativePath.replace(/\\/g, '/'));
|
|
191
233
|
if (progressBar) {
|
|
192
|
-
progressBar.
|
|
234
|
+
progressBar.init({ size: fileSize, name: filePosixPath });
|
|
193
235
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
236
|
+
const fileStream = fs.createReadStream(fileAbsolutePath);
|
|
237
|
+
fileStream.pause();
|
|
238
|
+
fileStream.on('data', (chunk) => {
|
|
239
|
+
if (progressBar) {
|
|
240
|
+
progressBar.update({ add: chunk.length, name: filePosixPath });
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
yield restApi.applet.version.file
|
|
244
|
+
.create(applet.uid, applet.version, {
|
|
245
|
+
name: path.basename(filePosixPath),
|
|
246
|
+
path: filePosixPath,
|
|
247
|
+
type: fileType,
|
|
248
|
+
hash: fileHash,
|
|
249
|
+
content: fileStream,
|
|
250
|
+
size: fileSize,
|
|
251
|
+
}, { build: false })
|
|
252
|
+
.catch((error) => {
|
|
253
|
+
if (error instanceof Error) {
|
|
254
|
+
throw new Error(`Failed to upload file "${fileAbsolutePath}": ${error.message}\n` +
|
|
255
|
+
`File details: Size=${fileSize} bytes, Type=${fileType}`);
|
|
256
|
+
}
|
|
257
|
+
throw error;
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
if (error instanceof Error) {
|
|
262
|
+
if (fileAbsolutePath) {
|
|
263
|
+
const enhancedError = new Error(`Failed to upload file "${fileAbsolutePath}": ${error.message}`);
|
|
264
|
+
// Preserve the original stack trace if available
|
|
265
|
+
if (error.stack) {
|
|
266
|
+
enhancedError.stack = error.stack;
|
|
267
|
+
}
|
|
268
|
+
throw enhancedError;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
throw error;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
206
274
|
}
|
|
207
275
|
finally {
|
|
208
276
|
if (progressBar) {
|
|
@@ -210,8 +278,12 @@ const createMultiFileFileApplet = (parameters) => __awaiter(void 0, void 0, void
|
|
|
210
278
|
}
|
|
211
279
|
}
|
|
212
280
|
// The extra update applet version which has to be after upload all files to trigger applet version build
|
|
213
|
-
yield restApi.applet.version.update(applet.uid, applet.version, {
|
|
214
|
-
|
|
281
|
+
yield restApi.applet.version.update(applet.uid, applet.version, { entryFile: appletEntryFilePosixPath }).catch((error) => {
|
|
282
|
+
if (error instanceof Error) {
|
|
283
|
+
throw new Error(`Failed to finalize applet version with entry file "${appletEntryFilePosixPath}": ${error.message}\n` +
|
|
284
|
+
`This usually happens when there were issues with one or more uploaded files or when building the applet.`);
|
|
285
|
+
}
|
|
286
|
+
throw error;
|
|
215
287
|
});
|
|
216
288
|
});
|
|
217
289
|
exports.createMultiFileFileApplet = createMultiFileFileApplet;
|