apify-cli 0.19.3-beta.5 → 1.0.0-beta.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 +73 -52
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +16 -0
- package/bin/run.js +16 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/commands/actor/get-input.d.ts +6 -0
- package/dist/commands/actor/get-input.d.ts.map +1 -0
- package/dist/commands/actor/get-input.js +14 -0
- package/dist/commands/actor/get-input.js.map +1 -0
- package/dist/commands/actor/get-value.d.ts +9 -0
- package/dist/commands/actor/get-value.d.ts.map +1 -0
- package/dist/commands/actor/get-value.js +27 -0
- package/dist/commands/actor/get-value.js.map +1 -0
- package/dist/commands/actor/index.d.ts +6 -0
- package/dist/commands/actor/index.d.ts.map +1 -0
- package/dist/commands/actor/index.js +13 -0
- package/dist/commands/actor/index.js.map +1 -0
- package/dist/commands/actor/push-data.d.ts +11 -0
- package/dist/commands/actor/push-data.d.ts.map +1 -0
- package/dist/commands/actor/push-data.js +56 -0
- package/dist/commands/actor/push-data.js.map +1 -0
- package/dist/commands/actor/set-value.d.ts +15 -0
- package/dist/commands/actor/set-value.d.ts.map +1 -0
- package/dist/commands/actor/set-value.js +76 -0
- package/dist/commands/actor/set-value.js.map +1 -0
- package/dist/commands/call.d.ts +15 -0
- package/dist/commands/call.d.ts.map +1 -0
- package/dist/commands/call.js +142 -0
- package/dist/commands/call.js.map +1 -0
- package/dist/commands/check-version.d.ts +11 -0
- package/dist/commands/check-version.d.ts.map +1 -0
- package/dist/commands/check-version.js +39 -0
- package/dist/commands/check-version.js.map +1 -0
- package/dist/commands/create.d.ts +14 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +181 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/edit-input-schema.d.ts +11 -0
- package/dist/commands/edit-input-schema.d.ts.map +1 -0
- package/{src → dist}/commands/edit-input-schema.js +81 -85
- package/dist/commands/edit-input-schema.js.map +1 -0
- package/dist/commands/info.d.ts +6 -0
- package/dist/commands/info.d.ts.map +1 -0
- package/dist/commands/info.js +26 -0
- package/dist/commands/info.js.map +1 -0
- package/dist/commands/init-wrap-scrapy.d.ts +10 -0
- package/dist/commands/init-wrap-scrapy.d.ts.map +1 -0
- package/dist/commands/init-wrap-scrapy.js +41 -0
- package/dist/commands/init-wrap-scrapy.js.map +1 -0
- package/dist/commands/init.d.ts +12 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +88 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/login-new.d.ts +10 -0
- package/dist/commands/login-new.d.ts.map +1 -0
- package/{src → dist}/commands/login-new.js +79 -82
- package/dist/commands/login-new.js.map +1 -0
- package/dist/commands/login.d.ts +9 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +43 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +6 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +20 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/pull.d.ts +12 -0
- package/dist/commands/pull.d.ts.map +1 -0
- package/dist/commands/pull.js +148 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/push.d.ts +16 -0
- package/dist/commands/push.d.ts.map +1 -0
- package/dist/commands/push.js +242 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/commands/run.d.ts +12 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/{src → dist}/commands/run.js +96 -109
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/secrets/add.d.ts +10 -0
- package/dist/commands/secrets/add.d.ts.map +1 -0
- package/dist/commands/secrets/add.js +31 -0
- package/dist/commands/secrets/add.js.map +1 -0
- package/dist/commands/secrets/index.d.ts +6 -0
- package/dist/commands/secrets/index.d.ts.map +1 -0
- package/dist/commands/secrets/index.js +24 -0
- package/dist/commands/secrets/index.js.map +1 -0
- package/dist/commands/secrets/rm.d.ts +9 -0
- package/dist/commands/secrets/rm.d.ts.map +1 -0
- package/dist/commands/secrets/rm.js +27 -0
- package/dist/commands/secrets/rm.js.map +1 -0
- package/dist/commands/vis.d.ts +9 -0
- package/dist/commands/vis.d.ts.map +1 -0
- package/dist/commands/vis.js +52 -0
- package/dist/commands/vis.js.map +1 -0
- package/dist/hooks/init.d.ts +7 -0
- package/dist/hooks/init.d.ts.map +1 -0
- package/dist/hooks/init.js +17 -0
- package/dist/hooks/init.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/actor.d.ts +27 -0
- package/dist/lib/actor.d.ts.map +1 -0
- package/{src → dist}/lib/actor.js +21 -44
- package/dist/lib/actor.js.map +1 -0
- package/dist/lib/apify-oclif-help.d.ts +15 -0
- package/dist/lib/apify-oclif-help.d.ts.map +1 -0
- package/dist/lib/apify-oclif-help.js +19 -0
- package/dist/lib/apify-oclif-help.js.map +1 -0
- package/dist/lib/apify_command.d.ts +22 -0
- package/dist/lib/apify_command.d.ts.map +1 -0
- package/dist/lib/apify_command.js +103 -0
- package/dist/lib/apify_command.js.map +1 -0
- package/dist/lib/community.d.ts +2 -0
- package/dist/lib/community.d.ts.map +1 -0
- package/dist/lib/community.js +4 -0
- package/dist/lib/community.js.map +1 -0
- package/dist/lib/consts.d.ts +45 -0
- package/dist/lib/consts.d.ts.map +1 -0
- package/dist/lib/consts.js +54 -0
- package/dist/lib/consts.js.map +1 -0
- package/dist/lib/create-utils.d.ts +8 -0
- package/dist/lib/create-utils.d.ts.map +1 -0
- package/{src → dist}/lib/create-utils.js +74 -113
- package/dist/lib/create-utils.js.map +1 -0
- package/dist/lib/exec.d.ts +4 -0
- package/dist/lib/exec.d.ts.map +1 -0
- package/{src → dist}/lib/exec.js +15 -16
- package/dist/lib/exec.js.map +1 -0
- package/dist/lib/files.d.ts +14 -0
- package/dist/lib/files.d.ts.map +1 -0
- package/dist/lib/files.js +58 -0
- package/dist/lib/files.js.map +1 -0
- package/dist/lib/input_schema.d.ts +26 -0
- package/dist/lib/input_schema.d.ts.map +1 -0
- package/{src → dist}/lib/input_schema.js +34 -55
- package/dist/lib/input_schema.js.map +1 -0
- package/dist/lib/local_state.d.ts +11 -0
- package/dist/lib/local_state.d.ts.map +1 -0
- package/dist/lib/local_state.js +27 -0
- package/dist/lib/local_state.js.map +1 -0
- package/dist/lib/outputs.d.ts +7 -0
- package/dist/lib/outputs.d.ts.map +1 -0
- package/{src → dist}/lib/outputs.js +8 -15
- package/dist/lib/outputs.js.map +1 -0
- package/dist/lib/project_analyzer.d.ts +4 -0
- package/dist/lib/project_analyzer.d.ts.map +1 -0
- package/{src → dist}/lib/project_analyzer.js +6 -11
- package/dist/lib/project_analyzer.js.map +1 -0
- package/dist/lib/projects/CrawleeAnalyzer.d.ts +4 -0
- package/dist/lib/projects/CrawleeAnalyzer.d.ts.map +1 -0
- package/{src → dist}/lib/projects/CrawleeAnalyzer.js +7 -24
- package/dist/lib/projects/CrawleeAnalyzer.js.map +1 -0
- package/dist/lib/projects/OldApifySDKAnalyzer.d.ts +4 -0
- package/dist/lib/projects/OldApifySDKAnalyzer.d.ts.map +1 -0
- package/{src → dist}/lib/projects/OldApifySDKAnalyzer.js +9 -32
- package/dist/lib/projects/OldApifySDKAnalyzer.js.map +1 -0
- package/dist/lib/projects/scrapy/ScrapyProjectAnalyzer.d.ts +17 -0
- package/dist/lib/projects/scrapy/ScrapyProjectAnalyzer.d.ts.map +1 -0
- package/{src/lib/scrapy-wrapper → dist/lib/projects/scrapy}/ScrapyProjectAnalyzer.js +33 -36
- package/dist/lib/projects/scrapy/ScrapyProjectAnalyzer.js.map +1 -0
- package/dist/lib/projects/scrapy/Spider.d.ts +14 -0
- package/dist/lib/projects/scrapy/Spider.d.ts.map +1 -0
- package/dist/lib/projects/scrapy/Spider.js +33 -0
- package/dist/lib/projects/scrapy/Spider.js.map +1 -0
- package/dist/lib/projects/scrapy/SpiderFileAnalyzer.d.ts +7 -0
- package/dist/lib/projects/scrapy/SpiderFileAnalyzer.d.ts.map +1 -0
- package/dist/lib/projects/scrapy/SpiderFileAnalyzer.js +25 -0
- package/dist/lib/projects/scrapy/SpiderFileAnalyzer.js.map +1 -0
- package/dist/lib/projects/scrapy/wrapScrapyProject.d.ts +4 -0
- package/dist/lib/projects/scrapy/wrapScrapyProject.d.ts.map +1 -0
- package/{src/lib/scrapy-wrapper/index.js → dist/lib/projects/scrapy/wrapScrapyProject.js} +43 -73
- package/dist/lib/projects/scrapy/wrapScrapyProject.js.map +1 -0
- package/dist/lib/projects/shared.d.ts +2 -0
- package/dist/lib/projects/shared.d.ts.map +1 -0
- package/dist/lib/projects/shared.js +13 -0
- package/dist/lib/projects/shared.js.map +1 -0
- package/dist/lib/secrets.d.ts +22 -0
- package/dist/lib/secrets.d.ts.map +1 -0
- package/{src → dist}/lib/secrets.js +32 -40
- package/dist/lib/secrets.js.map +1 -0
- package/dist/lib/telemetry.d.ts +21 -0
- package/dist/lib/telemetry.d.ts.map +1 -0
- package/dist/lib/telemetry.js +87 -0
- package/dist/lib/telemetry.js.map +1 -0
- package/dist/lib/types.d.ts +11 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +2 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/utils.d.ts +106 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/{src → dist}/lib/utils.js +235 -347
- package/dist/lib/utils.js.map +1 -0
- package/dist/lib/version_check.d.ts +14 -0
- package/dist/lib/version_check.d.ts.map +1 -0
- package/{src → dist}/lib/version_check.js +25 -54
- package/dist/lib/version_check.js.map +1 -0
- package/oclif.manifest.json +722 -1
- package/package.json +137 -113
- package/index.js +0 -1
- package/src/bin/run +0 -16
- package/src/commands/actor/get-input.js +0 -12
- package/src/commands/actor/get-value.js +0 -23
- package/src/commands/actor/index.js +0 -13
- package/src/commands/actor/push-data.js +0 -44
- package/src/commands/actor/set-value.js +0 -63
- package/src/commands/call.js +0 -131
- package/src/commands/check-version.js +0 -28
- package/src/commands/create.js +0 -203
- package/src/commands/info.js +0 -24
- package/src/commands/init-wrap-scrapy.js +0 -34
- package/src/commands/init.js +0 -84
- package/src/commands/login.js +0 -40
- package/src/commands/logout.js +0 -18
- package/src/commands/pull.js +0 -154
- package/src/commands/push.js +0 -234
- package/src/commands/secrets/add.js +0 -28
- package/src/commands/secrets/index.js +0 -24
- package/src/commands/secrets/rm.js +0 -23
- package/src/commands/vis.js +0 -50
- package/src/hooks/init.js +0 -16
- package/src/lib/apify-oclif-help.js +0 -23
- package/src/lib/apify_command.js +0 -82
- package/src/lib/community.js +0 -3
- package/src/lib/consts.js +0 -69
- package/src/lib/files.js +0 -76
- package/src/lib/local_state.js +0 -39
- package/src/lib/scrapy-wrapper/Spider.js +0 -10
- package/src/lib/scrapy-wrapper/SpiderFileAnalyzer.js +0 -26
- package/src/lib/telemetry.js +0 -104
- /package/{src/bin → bin}/run.cmd +0 -0
|
@@ -1,241 +1,183 @@
|
|
|
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
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const _ = require('underscore');
|
|
33
|
-
const writeJson = require('write-json-file');
|
|
34
|
-
|
|
35
|
-
const {
|
|
36
|
-
GLOBAL_CONFIGS_FOLDER,
|
|
37
|
-
AUTH_FILE_PATH,
|
|
38
|
-
INPUT_FILE_REG_EXP,
|
|
39
|
-
DEFAULT_LOCAL_STORAGE_DIR,
|
|
40
|
-
LOCAL_CONFIG_PATH,
|
|
41
|
-
DEPRECATED_LOCAL_CONFIG_NAME,
|
|
42
|
-
ACTOR_SPECIFICATION_VERSION,
|
|
43
|
-
APIFY_CLIENT_DEFAULT_HEADERS,
|
|
44
|
-
SUPPORTED_NODEJS_VERSION,
|
|
45
|
-
MINIMUM_SUPPORTED_PYTHON_VERSION,
|
|
46
|
-
LANGUAGE,
|
|
47
|
-
PROJECT_TYPES,
|
|
48
|
-
} = require('./consts');
|
|
49
|
-
const {
|
|
50
|
-
ensureFolderExistsSync,
|
|
51
|
-
rimrafPromised,
|
|
52
|
-
deleteFile,
|
|
53
|
-
} = require('./files');
|
|
54
|
-
const {
|
|
55
|
-
info,
|
|
56
|
-
} = require('./outputs');
|
|
57
|
-
const { ProjectAnalyzer } = require('./project_analyzer');
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* @param {string} url
|
|
61
|
-
* @returns {Promise<unknown>}
|
|
62
|
-
*/
|
|
63
|
-
const httpsGet = async (url) => {
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { get } from 'node:https';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
import process from 'node:process';
|
|
6
|
+
import { finished } from 'node:stream/promises';
|
|
7
|
+
import { ACTOR_ENV_VARS, ACTOR_JOB_TERMINAL_STATUSES, ACTOR_NAME, APIFY_ENV_VARS, KEY_VALUE_STORE_KEYS, LOCAL_ACTOR_ENV_VARS, LOCAL_STORAGE_SUBDIRS, SOURCE_FILE_FORMATS, } from '@apify/consts';
|
|
8
|
+
import AdmZip from 'adm-zip';
|
|
9
|
+
import _Ajv from 'ajv';
|
|
10
|
+
import { ApifyClient } from 'apify-client';
|
|
11
|
+
import archiver from 'archiver';
|
|
12
|
+
import { AxiosHeaders } from 'axios';
|
|
13
|
+
import escapeStringRegexp from 'escape-string-regexp';
|
|
14
|
+
import { globby } from 'globby';
|
|
15
|
+
import inquirer from 'inquirer';
|
|
16
|
+
import { getEncoding } from 'istextorbinary';
|
|
17
|
+
import { loadJsonFile, loadJsonFileSync } from 'load-json-file';
|
|
18
|
+
import { Mime } from 'mime';
|
|
19
|
+
import otherMimes from 'mime/types/other.js';
|
|
20
|
+
import standardMimes from 'mime/types/standard.js';
|
|
21
|
+
import { gte, minVersion, satisfies } from 'semver';
|
|
22
|
+
import _ from 'underscore';
|
|
23
|
+
import { writeJsonFile, writeJsonFileSync } from 'write-json-file';
|
|
24
|
+
import { ACTOR_SPECIFICATION_VERSION, APIFY_CLIENT_DEFAULT_HEADERS, AUTH_FILE_PATH, DEFAULT_LOCAL_STORAGE_DIR, DEPRECATED_LOCAL_CONFIG_NAME, GLOBAL_CONFIGS_FOLDER, INPUT_FILE_REG_EXP, LANGUAGE, LOCAL_CONFIG_PATH, MINIMUM_SUPPORTED_PYTHON_VERSION, PROJECT_TYPES, SUPPORTED_NODEJS_VERSION, } from './consts.js';
|
|
25
|
+
import { deleteFile, ensureFolderExistsSync, rimrafPromised } from './files.js';
|
|
26
|
+
import { info } from './outputs.js';
|
|
27
|
+
import { ProjectAnalyzer } from './project_analyzer.js';
|
|
28
|
+
// Export AJV properly: https://github.com/ajv-validator/ajv/issues/2132
|
|
29
|
+
// Welcome to the state of JavaScript/TypeScript and CJS/ESM interop.
|
|
30
|
+
export const Ajv = _Ajv;
|
|
31
|
+
export const httpsGet = async (url) => {
|
|
64
32
|
return new Promise((resolve, reject) => {
|
|
65
|
-
|
|
33
|
+
get(url, (response) => {
|
|
66
34
|
// Handle redirects
|
|
67
35
|
if (response.statusCode === 301 || response.statusCode === 302) {
|
|
68
36
|
resolve(httpsGet(response.headers.location));
|
|
69
37
|
// Destroy the response to close the HTTP connection, otherwise this hangs for a long time with Node 19+ (due to HTTP keep-alive).
|
|
70
38
|
response.destroy();
|
|
71
|
-
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
72
41
|
resolve(response);
|
|
73
42
|
}
|
|
74
43
|
}).on('error', reject);
|
|
75
44
|
});
|
|
76
45
|
};
|
|
77
|
-
|
|
78
46
|
// Properties from apify.json file that will me migrated to actor specs in .actor/actor.json
|
|
79
47
|
const MIGRATED_APIFY_JSON_PROPERTIES = ['name', 'version', 'buildTag'];
|
|
80
|
-
|
|
81
|
-
const getLocalStorageDir = () => {
|
|
48
|
+
export const getLocalStorageDir = () => {
|
|
82
49
|
const envVar = APIFY_ENV_VARS.LOCAL_STORAGE_DIR;
|
|
83
|
-
|
|
84
50
|
return process.env[envVar] || process.env.CRAWLEE_STORAGE_DIR || DEFAULT_LOCAL_STORAGE_DIR;
|
|
85
51
|
};
|
|
86
|
-
const getLocalKeyValueStorePath = (storeId) => {
|
|
52
|
+
export const getLocalKeyValueStorePath = (storeId) => {
|
|
87
53
|
const envVar = ACTOR_ENV_VARS.DEFAULT_KEY_VALUE_STORE_ID;
|
|
88
54
|
const storeDir = storeId || process.env[envVar] || LOCAL_ACTOR_ENV_VARS[envVar];
|
|
89
|
-
|
|
90
|
-
return path.join(getLocalStorageDir(), LOCAL_STORAGE_SUBDIRS.keyValueStores, storeDir);
|
|
55
|
+
return join(getLocalStorageDir(), LOCAL_STORAGE_SUBDIRS.keyValueStores, storeDir);
|
|
91
56
|
};
|
|
92
|
-
const getLocalDatasetPath = (storeId) => {
|
|
57
|
+
export const getLocalDatasetPath = (storeId) => {
|
|
93
58
|
const envVar = ACTOR_ENV_VARS.DEFAULT_DATASET_ID;
|
|
94
59
|
const storeDir = storeId || process.env[envVar] || LOCAL_ACTOR_ENV_VARS[envVar];
|
|
95
|
-
|
|
96
|
-
return path.join(getLocalStorageDir(), LOCAL_STORAGE_SUBDIRS.datasets, storeDir);
|
|
60
|
+
return join(getLocalStorageDir(), LOCAL_STORAGE_SUBDIRS.datasets, storeDir);
|
|
97
61
|
};
|
|
98
|
-
const getLocalRequestQueuePath = (storeId) => {
|
|
62
|
+
export const getLocalRequestQueuePath = (storeId) => {
|
|
99
63
|
const envVar = ACTOR_ENV_VARS.DEFAULT_REQUEST_QUEUE_ID;
|
|
100
64
|
const storeDir = storeId || process.env[envVar] || LOCAL_ACTOR_ENV_VARS[envVar];
|
|
101
|
-
|
|
102
|
-
return path.join(getLocalStorageDir(), LOCAL_STORAGE_SUBDIRS.requestQueues, storeDir);
|
|
65
|
+
return join(getLocalStorageDir(), LOCAL_STORAGE_SUBDIRS.requestQueues, storeDir);
|
|
103
66
|
};
|
|
104
|
-
|
|
105
67
|
/**
|
|
106
68
|
* Returns object from auth file or empty object.
|
|
107
|
-
* @return {*}
|
|
108
69
|
*/
|
|
109
|
-
const getLocalUserInfo = () => {
|
|
70
|
+
export const getLocalUserInfo = async () => {
|
|
110
71
|
try {
|
|
111
|
-
|
|
112
|
-
|
|
72
|
+
const result = await loadJsonFile(AUTH_FILE_PATH());
|
|
73
|
+
return (result || {});
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
113
76
|
return {};
|
|
114
77
|
}
|
|
115
78
|
};
|
|
116
|
-
|
|
117
79
|
/**
|
|
118
80
|
* Gets instance of ApifyClient for user otherwise throws error
|
|
119
|
-
* @return {Promise<boolean|*>}
|
|
120
81
|
*/
|
|
121
|
-
const getLoggedClientOrThrow = async () => {
|
|
82
|
+
export const getLoggedClientOrThrow = async () => {
|
|
122
83
|
const loggedClient = await getLoggedClient();
|
|
123
84
|
if (!loggedClient) {
|
|
124
85
|
throw new Error('You are not logged in with your Apify account. Call "apify login" to fix that.');
|
|
125
86
|
}
|
|
126
87
|
return loggedClient;
|
|
127
88
|
};
|
|
128
|
-
|
|
89
|
+
const getTokenWithAuthFileFallback = (existingToken) => {
|
|
90
|
+
if (!existingToken && existsSync(GLOBAL_CONFIGS_FOLDER()) && existsSync(AUTH_FILE_PATH())) {
|
|
91
|
+
return loadJsonFileSync(AUTH_FILE_PATH()).token;
|
|
92
|
+
}
|
|
93
|
+
return existingToken;
|
|
94
|
+
};
|
|
129
95
|
/**
|
|
130
96
|
* Returns options for ApifyClient
|
|
131
|
-
* @param {String|null|undefined} token
|
|
132
|
-
* @returns {Object}
|
|
133
97
|
*/
|
|
134
|
-
const getApifyClientOptions = (token, apiBaseUrl) => {
|
|
135
|
-
|
|
136
|
-
({ token } = loadJson.sync(AUTH_FILE_PATH));
|
|
137
|
-
}
|
|
138
|
-
|
|
98
|
+
export const getApifyClientOptions = (token, apiBaseUrl) => {
|
|
99
|
+
token = getTokenWithAuthFileFallback(token);
|
|
139
100
|
return {
|
|
140
101
|
token,
|
|
141
102
|
baseUrl: apiBaseUrl || process.env.APIFY_CLIENT_BASE_URL,
|
|
142
103
|
requestInterceptors: [(config) => {
|
|
143
|
-
|
|
144
|
-
config.headers = new
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
config
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return config;
|
|
152
|
-
}],
|
|
104
|
+
// @ts-expect-error CLI is ESM, client is CJS, the types "differ"
|
|
105
|
+
config.headers ?? (config.headers = new AxiosHeaders());
|
|
106
|
+
for (const [key, value] of Object.entries(APIFY_CLIENT_DEFAULT_HEADERS)) {
|
|
107
|
+
config.headers[key] = value;
|
|
108
|
+
}
|
|
109
|
+
return config;
|
|
110
|
+
}],
|
|
153
111
|
};
|
|
154
112
|
};
|
|
155
|
-
|
|
156
113
|
/**
|
|
157
114
|
* Gets instance of ApifyClient for token or for params from global auth file.
|
|
158
115
|
* NOTE: It refreshes global auth file each run
|
|
159
116
|
* @param [token]
|
|
160
|
-
* @return {Promise<*>}
|
|
161
117
|
*/
|
|
162
|
-
const getLoggedClient = async (token, apiBaseUrl) => {
|
|
163
|
-
|
|
164
|
-
({ token } = loadJson.sync(AUTH_FILE_PATH));
|
|
165
|
-
}
|
|
166
|
-
|
|
118
|
+
export const getLoggedClient = async (token, apiBaseUrl) => {
|
|
119
|
+
token = getTokenWithAuthFileFallback(token);
|
|
167
120
|
const apifyClient = new ApifyClient(getApifyClientOptions(token, apiBaseUrl));
|
|
168
121
|
let userInfo;
|
|
169
122
|
try {
|
|
170
123
|
userInfo = await apifyClient.user('me').get();
|
|
171
|
-
} catch (e) {
|
|
172
|
-
return false;
|
|
173
124
|
}
|
|
174
|
-
|
|
125
|
+
catch (err) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
175
128
|
// Always refresh Auth file
|
|
176
|
-
|
|
177
|
-
|
|
129
|
+
ensureApifyDirectory(AUTH_FILE_PATH());
|
|
130
|
+
await writeJsonFile(AUTH_FILE_PATH(), { token: apifyClient.token, ...userInfo });
|
|
178
131
|
return apifyClient;
|
|
179
132
|
};
|
|
180
|
-
|
|
181
|
-
const getLocalConfigPath = () => path.join(process.cwd(), LOCAL_CONFIG_PATH);
|
|
182
|
-
|
|
133
|
+
const getLocalConfigPath = (cwd) => join(cwd, LOCAL_CONFIG_PATH);
|
|
183
134
|
/**
|
|
184
135
|
* @deprecated Use getLocalConfigPath
|
|
185
|
-
* @returns {string}
|
|
186
136
|
*/
|
|
187
|
-
const getDeprecatedLocalConfigPath = () =>
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
if (!fs.existsSync(filePath)) {
|
|
137
|
+
const getDeprecatedLocalConfigPath = (cwd) => join(cwd, DEPRECATED_LOCAL_CONFIG_NAME);
|
|
138
|
+
export const getJsonFileContent = (filePath) => {
|
|
139
|
+
if (!existsSync(filePath)) {
|
|
191
140
|
return;
|
|
192
141
|
}
|
|
193
|
-
return
|
|
142
|
+
return loadJsonFileSync(filePath);
|
|
194
143
|
};
|
|
195
|
-
|
|
196
|
-
const getLocalConfig = () => getJsonFileContent(getLocalConfigPath());
|
|
197
|
-
|
|
144
|
+
export const getLocalConfig = (cwd) => getJsonFileContent(getLocalConfigPath(cwd));
|
|
198
145
|
/**
|
|
199
146
|
* @deprecated Use getLocalConfig
|
|
200
|
-
* @returns {string}
|
|
201
147
|
*/
|
|
202
|
-
const getDeprecatedLocalConfig = () => getJsonFileContent(getDeprecatedLocalConfigPath());
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
let
|
|
206
|
-
let deprecatedLocalConfig = getDeprecatedLocalConfig();
|
|
207
|
-
|
|
148
|
+
const getDeprecatedLocalConfig = (cwd) => getJsonFileContent(getDeprecatedLocalConfigPath(cwd));
|
|
149
|
+
export const getLocalConfigOrThrow = async (cwd) => {
|
|
150
|
+
let localConfig = getLocalConfig(cwd);
|
|
151
|
+
let deprecatedLocalConfig = getDeprecatedLocalConfig(cwd);
|
|
208
152
|
if (localConfig && deprecatedLocalConfig) {
|
|
209
153
|
const answer = await inquirer.prompt([{
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}]);
|
|
154
|
+
name: 'isConfirm',
|
|
155
|
+
type: 'confirm',
|
|
156
|
+
message: `The new version of Apify CLI uses the "${LOCAL_CONFIG_PATH}" instead of the "apify.json" file. Since we have found both files in your Actor directory, "apify.json" will be renamed to "apify.json.deprecated". Going forward, all commands will use "${LOCAL_CONFIG_PATH}". You can read about the differences between the old and the new config at https://github.com/apify/apify-cli/blob/master/MIGRATIONS.md. Do you want to continue?`,
|
|
157
|
+
}]);
|
|
215
158
|
if (!answer.isConfirm) {
|
|
216
159
|
throw new Error('Command can not run with old "apify.json" file present in your Actor directory., Please, either rename or remove it.');
|
|
217
160
|
}
|
|
218
161
|
try {
|
|
219
|
-
|
|
162
|
+
renameSync(getDeprecatedLocalConfigPath(cwd), `${getDeprecatedLocalConfigPath(cwd)}.deprecated`);
|
|
220
163
|
// eslint-disable-next-line max-len
|
|
221
164
|
info(`The "apify.json" file has been renamed to "apify.json.deprecated". The deprecated file is no longer used by the CLI or Apify Console. If you do not need it for some specific purpose, it can be safely deleted.`);
|
|
222
|
-
}
|
|
165
|
+
}
|
|
166
|
+
catch (e) {
|
|
223
167
|
throw new Error('Failed to rename deprecated "apify.json".');
|
|
224
168
|
}
|
|
225
169
|
}
|
|
226
|
-
|
|
227
170
|
if (!localConfig && !deprecatedLocalConfig) {
|
|
228
171
|
return {};
|
|
229
172
|
}
|
|
230
|
-
|
|
231
173
|
// If apify.json exists migrate it to .actor/actor.json
|
|
232
174
|
if (!localConfig && deprecatedLocalConfig) {
|
|
233
175
|
const answer = await inquirer.prompt([{
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
176
|
+
name: 'isConfirm',
|
|
177
|
+
type: 'confirm',
|
|
178
|
+
// eslint-disable-next-line max-len
|
|
179
|
+
message: `The new version of Apify CLI uses the "${LOCAL_CONFIG_PATH}" instead of the "apify.json" file. Your "apify.json" file will be automatically updated to the new format under "${LOCAL_CONFIG_PATH}". The original file will be renamed by adding the ".deprecated" suffix. Do you want to continue?`,
|
|
180
|
+
}]);
|
|
239
181
|
if (!answer.isConfirm) {
|
|
240
182
|
throw new Error('Command can not run with old apify.json structure. Either let the CLI auto-update it or follow the guide on https://github.com/apify/apify-cli/blob/master/MIGRATIONS.md and update it manually.');
|
|
241
183
|
}
|
|
@@ -246,87 +188,77 @@ const getLocalConfigOrThrow = async () => {
|
|
|
246
188
|
}
|
|
247
189
|
localConfig = {
|
|
248
190
|
actorSpecification: ACTOR_SPECIFICATION_VERSION,
|
|
249
|
-
environmentVariables: deprecatedLocalConfig
|
|
191
|
+
environmentVariables: deprecatedLocalConfig?.env || undefined,
|
|
250
192
|
..._.pick(deprecatedLocalConfig, MIGRATED_APIFY_JSON_PROPERTIES),
|
|
251
193
|
};
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
fs.renameSync(getDeprecatedLocalConfigPath(), `${getDeprecatedLocalConfigPath()}.deprecated`);
|
|
194
|
+
await writeJsonFile(getLocalConfigPath(cwd), localConfig);
|
|
195
|
+
renameSync(getDeprecatedLocalConfigPath(cwd), `${getDeprecatedLocalConfigPath(cwd)}.deprecated`);
|
|
255
196
|
// eslint-disable-next-line max-len
|
|
256
197
|
info(`The "apify.json" file has been migrated to "${LOCAL_CONFIG_PATH}" and the original file renamed to "apify.json.deprecated". The deprecated file is no longer used by the CLI or Apify Console. If you do not need it for some specific purpose, it can be safely deleted. Do not forget to commit the new file to your Git repository.`);
|
|
257
|
-
}
|
|
198
|
+
}
|
|
199
|
+
catch (e) {
|
|
258
200
|
throw new Error(`Can not update "${LOCAL_CONFIG_PATH}" structure. Follow guide on https://github.com/apify/apify-cli/blob/master/MIGRATIONS.md and update it manually.`);
|
|
259
201
|
}
|
|
260
202
|
}
|
|
261
|
-
|
|
262
203
|
return localConfig;
|
|
263
204
|
};
|
|
264
|
-
|
|
265
|
-
const setLocalConfig = async (localConfig, actDir) => {
|
|
205
|
+
export const setLocalConfig = async (localConfig, actDir) => {
|
|
266
206
|
actDir = actDir || process.cwd();
|
|
267
|
-
|
|
207
|
+
writeJsonFileSync(join(actDir, LOCAL_CONFIG_PATH), localConfig);
|
|
268
208
|
};
|
|
269
|
-
|
|
270
209
|
const GITIGNORE_REQUIRED_CONTENTS = [getLocalStorageDir(), 'node_modules', '.venv'];
|
|
271
|
-
|
|
272
|
-
const setLocalEnv = async (actDir) => {
|
|
210
|
+
export const setLocalEnv = async (actDir) => {
|
|
273
211
|
// Create folders for emulation Apify stores
|
|
274
212
|
const keyValueStorePath = getLocalKeyValueStorePath();
|
|
275
213
|
ensureFolderExistsSync(actDir, getLocalDatasetPath());
|
|
276
214
|
ensureFolderExistsSync(actDir, getLocalRequestQueuePath());
|
|
277
215
|
ensureFolderExistsSync(actDir, keyValueStorePath);
|
|
278
|
-
|
|
279
216
|
// Create or update gitignore
|
|
280
|
-
const gitignorePath =
|
|
217
|
+
const gitignorePath = join(actDir, '.gitignore');
|
|
281
218
|
let gitignoreContents = '';
|
|
282
|
-
if (
|
|
283
|
-
gitignoreContents =
|
|
219
|
+
if (existsSync(gitignorePath)) {
|
|
220
|
+
gitignoreContents = readFileSync(gitignorePath, { encoding: 'utf-8' });
|
|
284
221
|
}
|
|
285
|
-
|
|
286
222
|
const gitignoreAdditions = [];
|
|
287
223
|
for (const gitignoreRequirement of GITIGNORE_REQUIRED_CONTENTS) {
|
|
288
224
|
if (!RegExp(`^${escapeStringRegexp(gitignoreRequirement)}$`, 'mg').test(gitignoreContents)) {
|
|
289
225
|
gitignoreAdditions.push(gitignoreRequirement);
|
|
290
226
|
}
|
|
291
227
|
}
|
|
292
|
-
|
|
293
228
|
if (gitignoreAdditions.length > 0) {
|
|
294
229
|
if (gitignoreContents.length > 0) {
|
|
295
230
|
gitignoreAdditions.unshift('# Added by Apify CLI');
|
|
296
|
-
|
|
297
|
-
}
|
|
298
|
-
|
|
231
|
+
writeFileSync(gitignorePath, `\n${gitignoreAdditions.join('\n')}\n`, { flag: 'a' });
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
writeFileSync(gitignorePath, `${gitignoreAdditions.join('\n')}\n`, { flag: 'w' });
|
|
299
235
|
}
|
|
300
236
|
}
|
|
301
237
|
};
|
|
302
|
-
|
|
303
238
|
/**
|
|
304
239
|
* Convert Object with kebab-case keys to camelCased keys
|
|
305
|
-
*
|
|
306
|
-
* @param object
|
|
307
|
-
* @return {{}}
|
|
308
240
|
*/
|
|
309
|
-
const argsToCamelCase = (object) => {
|
|
241
|
+
export const argsToCamelCase = (object) => {
|
|
310
242
|
const camelCasedObject = {};
|
|
311
243
|
Object.keys(object).forEach((arg) => {
|
|
312
244
|
const camelCasedArg = arg.replace(/-(.)/g, ($1) => $1.toUpperCase()).replace(/-/g, '');
|
|
245
|
+
// @ts-expect-error This is very hard to make stricter than it already will be at the top level
|
|
313
246
|
camelCasedObject[camelCasedArg] = object[arg];
|
|
314
247
|
});
|
|
315
248
|
return camelCasedObject;
|
|
316
249
|
};
|
|
317
|
-
|
|
250
|
+
const mime = new Mime(standardMimes, otherMimes).define({
|
|
251
|
+
// .tgz files don't have a MIME type defined, this fixes it
|
|
252
|
+
'application/gzip': ['tgz'],
|
|
253
|
+
// Default mime-type for .ts(x) files is video/mp2t. But in our usecases they're almost always TypeScript, which we want to treat as text
|
|
254
|
+
'text/typescript': ['ts', 'tsx', 'mts'],
|
|
255
|
+
}, true);
|
|
318
256
|
// Detect whether file is binary from its MIME type, or if not available, contents
|
|
319
257
|
const getSourceFileFormat = (filePath, fileContent) => {
|
|
320
258
|
// Try to detect the MIME type from the file path
|
|
321
|
-
// .tgz files don't have a MIME type defined, this fixes it
|
|
322
|
-
mime.define({ 'application/gzip': ['tgz'] }, true);
|
|
323
|
-
// Default mime-type for .ts(x) files is video/mp2t. But in our usecases they're almost always TypeScript, which we want to treat as text
|
|
324
|
-
mime.define({ 'text/typescript': ['ts', 'tsx', 'mts'] }, true);
|
|
325
|
-
|
|
326
259
|
const contentType = mime.getType(filePath);
|
|
327
260
|
if (contentType) {
|
|
328
|
-
const format = (
|
|
329
|
-
contentType.startsWith('text/')
|
|
261
|
+
const format = (contentType.startsWith('text/')
|
|
330
262
|
|| contentType.includes('javascript')
|
|
331
263
|
|| contentType.includes('json')
|
|
332
264
|
|| contentType.includes('xml')
|
|
@@ -338,15 +270,13 @@ const getSourceFileFormat = (filePath, fileContent) => {
|
|
|
338
270
|
: SOURCE_FILE_FORMATS.BASE64;
|
|
339
271
|
return format;
|
|
340
272
|
}
|
|
341
|
-
|
|
342
273
|
// If the MIME type detection failed, try to detect the file encoding from the file content
|
|
343
274
|
const encoding = getEncoding(fileContent);
|
|
344
275
|
return encoding === 'binary' ? SOURCE_FILE_FORMATS.BASE64 : SOURCE_FILE_FORMATS.TEXT;
|
|
345
276
|
};
|
|
346
|
-
|
|
347
|
-
const createSourceFiles = async (paths) => {
|
|
277
|
+
export const createSourceFiles = async (paths, cwd) => {
|
|
348
278
|
return paths.map((filePath) => {
|
|
349
|
-
const file =
|
|
279
|
+
const file = readFileSync(join(cwd, filePath));
|
|
350
280
|
const format = getSourceFileFormat(filePath, file);
|
|
351
281
|
return {
|
|
352
282
|
name: filePath,
|
|
@@ -357,138 +287,144 @@ const createSourceFiles = async (paths) => {
|
|
|
357
287
|
};
|
|
358
288
|
});
|
|
359
289
|
};
|
|
360
|
-
|
|
361
290
|
/**
|
|
362
291
|
* Get actor local files, omit files defined in .gitignore and .git folder
|
|
363
292
|
* All dot files(.file) and folders(.folder/) are included.
|
|
364
293
|
*/
|
|
365
|
-
const getActorLocalFilePaths = () => globby(['*', '**/**'], {
|
|
294
|
+
export const getActorLocalFilePaths = async (cwd) => globby(['*', '**/**'], {
|
|
366
295
|
ignore: ['.git/**', 'apify_storage', 'node_modules', 'storage', 'crawlee_storage'],
|
|
367
296
|
gitignore: true,
|
|
368
297
|
dot: true,
|
|
298
|
+
cwd,
|
|
369
299
|
});
|
|
370
|
-
|
|
371
300
|
/**
|
|
372
301
|
* Create zip file with all actor files specified with pathsToZip
|
|
373
|
-
* @param zipName
|
|
374
|
-
* @param pathsToZip
|
|
375
|
-
* @return {Promise<void>}
|
|
376
302
|
*/
|
|
377
|
-
const createActZip = async (zipName, pathsToZip) => {
|
|
303
|
+
export const createActZip = async (zipName, pathsToZip, cwd) => {
|
|
378
304
|
// NOTE: There can be a zip from a previous unfinished operation.
|
|
379
|
-
if (
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
const
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
305
|
+
if (existsSync(zipName)) {
|
|
306
|
+
await deleteFile(zipName);
|
|
307
|
+
}
|
|
308
|
+
const writeStream = createWriteStream(zipName);
|
|
309
|
+
const archive = archiver('zip');
|
|
310
|
+
archive.pipe(writeStream);
|
|
311
|
+
pathsToZip.forEach((globPath) => archive.glob(globPath, { cwd }));
|
|
387
312
|
await archive.finalize();
|
|
388
313
|
};
|
|
389
|
-
|
|
390
314
|
/**
|
|
391
315
|
* Get actor input from local store
|
|
392
|
-
* @return {{body: *, contentType: string}}
|
|
393
316
|
*/
|
|
394
|
-
const getLocalInput = () => {
|
|
317
|
+
export const getLocalInput = (cwd) => {
|
|
395
318
|
const defaultLocalStorePath = getLocalKeyValueStorePath();
|
|
396
|
-
const files =
|
|
319
|
+
const files = readdirSync(join(cwd, defaultLocalStorePath));
|
|
397
320
|
const inputName = files.find((file) => !!file.match(INPUT_FILE_REG_EXP));
|
|
398
|
-
|
|
399
321
|
// No input file
|
|
400
|
-
if (!inputName)
|
|
401
|
-
|
|
402
|
-
const input =
|
|
322
|
+
if (!inputName)
|
|
323
|
+
return;
|
|
324
|
+
const input = readFileSync(join(cwd, defaultLocalStorePath, inputName));
|
|
403
325
|
const contentType = mime.getType(inputName);
|
|
404
326
|
return { body: input, contentType };
|
|
405
327
|
};
|
|
406
|
-
|
|
407
|
-
const purgeDefaultQueue = async () => {
|
|
328
|
+
export const purgeDefaultQueue = async () => {
|
|
408
329
|
const defaultQueuesPath = getLocalRequestQueuePath();
|
|
409
|
-
if (
|
|
330
|
+
if (existsSync(getLocalStorageDir()) && existsSync(defaultQueuesPath)) {
|
|
410
331
|
await rimrafPromised(defaultQueuesPath);
|
|
411
332
|
}
|
|
412
333
|
};
|
|
413
|
-
|
|
414
|
-
const purgeDefaultDataset = async () => {
|
|
334
|
+
export const purgeDefaultDataset = async () => {
|
|
415
335
|
const defaultDatasetPath = getLocalDatasetPath();
|
|
416
|
-
if (
|
|
336
|
+
if (existsSync(getLocalStorageDir()) && existsSync(defaultDatasetPath)) {
|
|
417
337
|
await rimrafPromised(defaultDatasetPath);
|
|
418
338
|
}
|
|
419
339
|
};
|
|
420
|
-
|
|
421
|
-
const purgeDefaultKeyValueStore = async () => {
|
|
340
|
+
export const purgeDefaultKeyValueStore = async () => {
|
|
422
341
|
const defaultKeyValueStorePath = getLocalKeyValueStorePath();
|
|
423
|
-
if (!
|
|
342
|
+
if (!existsSync(getLocalStorageDir()) || !existsSync(defaultKeyValueStorePath)) {
|
|
424
343
|
return;
|
|
425
344
|
}
|
|
426
|
-
const filesToDelete =
|
|
427
|
-
|
|
345
|
+
const filesToDelete = readdirSync(defaultKeyValueStorePath);
|
|
428
346
|
const deletePromises = [];
|
|
429
347
|
filesToDelete.forEach((file) => {
|
|
430
|
-
if (!file.match(INPUT_FILE_REG_EXP))
|
|
348
|
+
if (!file.match(INPUT_FILE_REG_EXP)) {
|
|
349
|
+
deletePromises.push(deleteFile(join(defaultKeyValueStorePath, file)));
|
|
350
|
+
}
|
|
431
351
|
});
|
|
432
|
-
|
|
433
352
|
await Promise.all(deletePromises);
|
|
434
353
|
};
|
|
435
|
-
|
|
436
|
-
const outputJobLog = async (job, timeout) => {
|
|
354
|
+
export const outputJobLog = async (job, timeout) => {
|
|
437
355
|
const { id: logId, status } = job;
|
|
356
|
+
const apifyClient = new ApifyClient({ baseUrl: process.env.APIFY_CLIENT_BASE_URL });
|
|
438
357
|
// In case job was already done just output log
|
|
439
|
-
if (
|
|
440
|
-
const apifyClient = new ApifyClient({ baseUrl: process.env.APIFY_CLIENT_BASE_URL });
|
|
358
|
+
if (ACTOR_JOB_TERMINAL_STATUSES.includes(status)) {
|
|
441
359
|
const log = await apifyClient.log(logId).get();
|
|
442
360
|
process.stdout.write(log);
|
|
361
|
+
return;
|
|
443
362
|
}
|
|
444
|
-
|
|
445
363
|
// In other case stream it to stdout
|
|
446
|
-
//
|
|
447
|
-
return new Promise((resolve
|
|
448
|
-
const
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
});
|
|
457
|
-
});
|
|
458
|
-
req.on('error', (err) => {
|
|
459
|
-
reject(err);
|
|
364
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
365
|
+
return new Promise(async (resolve) => {
|
|
366
|
+
const stream = await apifyClient.log(logId).stream();
|
|
367
|
+
if (!stream) {
|
|
368
|
+
resolve('no-logs');
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
let nodeTimeout = null;
|
|
372
|
+
stream.on('data', (chunk) => {
|
|
373
|
+
process.stdout.write(chunk.toString());
|
|
460
374
|
});
|
|
461
|
-
|
|
375
|
+
stream.once('end', () => {
|
|
462
376
|
resolve('finished');
|
|
377
|
+
if (nodeTimeout) {
|
|
378
|
+
clearTimeout(nodeTimeout);
|
|
379
|
+
}
|
|
463
380
|
});
|
|
464
|
-
|
|
465
381
|
if (timeout) {
|
|
466
|
-
setTimeout(() => {
|
|
467
|
-
|
|
468
|
-
if (req) {
|
|
469
|
-
req.removeAllListeners();
|
|
470
|
-
req.abort();
|
|
471
|
-
}
|
|
382
|
+
nodeTimeout = setTimeout(() => {
|
|
383
|
+
stream.destroy();
|
|
472
384
|
resolve('timeouts');
|
|
473
385
|
}, timeout);
|
|
474
386
|
}
|
|
475
387
|
});
|
|
388
|
+
// return new Promise((resolve, reject) => {
|
|
389
|
+
// const req = get(`https://api.apify.com/v2/logs/${logId}?stream=1`);
|
|
390
|
+
// let res: IncomingMessage;
|
|
391
|
+
// req.on('response', (response) => {
|
|
392
|
+
// res = response;
|
|
393
|
+
// response.on('data', (chunk) => process.stdout.write(chunk.toString()));
|
|
394
|
+
// response.on('error', (err) => {
|
|
395
|
+
// reject(err);
|
|
396
|
+
// });
|
|
397
|
+
// });
|
|
398
|
+
// req.on('error', (err) => {
|
|
399
|
+
// reject(err);
|
|
400
|
+
// });
|
|
401
|
+
// req.on('close', () => {
|
|
402
|
+
// resolve('finished');
|
|
403
|
+
// });
|
|
404
|
+
// if (timeout) {
|
|
405
|
+
// setTimeout(() => {
|
|
406
|
+
// if (res) res.removeAllListeners();
|
|
407
|
+
// if (req) {
|
|
408
|
+
// req.removeAllListeners();
|
|
409
|
+
// req.destroy();
|
|
410
|
+
// }
|
|
411
|
+
// resolve('timeouts');
|
|
412
|
+
// }, timeout);
|
|
413
|
+
// }
|
|
414
|
+
// });
|
|
476
415
|
};
|
|
477
|
-
|
|
478
416
|
/**
|
|
479
417
|
* Returns npm command for current os
|
|
480
418
|
* NOTE: For window we have to returns npm.cmd instead of npm, otherwise it doesn't work
|
|
481
419
|
* @return {string}
|
|
482
420
|
*/
|
|
483
|
-
const getNpmCmd = () => {
|
|
421
|
+
export const getNpmCmd = () => {
|
|
484
422
|
return /^win/.test(process.platform) ? 'npm.cmd' : 'npm';
|
|
485
423
|
};
|
|
486
|
-
|
|
487
424
|
/**
|
|
488
425
|
* Returns true if apify storage is empty (expect INPUT.*)
|
|
489
|
-
* @return {Promise<boolean>}
|
|
490
426
|
*/
|
|
491
|
-
const checkIfStorageIsEmpty = async () => {
|
|
427
|
+
export const checkIfStorageIsEmpty = async () => {
|
|
492
428
|
const filesWithoutInput = await globby([
|
|
493
429
|
`${getLocalStorageDir()}/**`,
|
|
494
430
|
// Omit INPUT.* file
|
|
@@ -496,20 +432,10 @@ const checkIfStorageIsEmpty = async () => {
|
|
|
496
432
|
]);
|
|
497
433
|
return filesWithoutInput.length === 0;
|
|
498
434
|
};
|
|
499
|
-
|
|
500
|
-
/**
|
|
501
|
-
* Show help for command
|
|
502
|
-
* NOTE: This is not nice, but I can not find other way..
|
|
503
|
-
* @param command
|
|
504
|
-
*/
|
|
505
|
-
const showHelpForCommand = (command) => {
|
|
506
|
-
execSync(`apify ${command} --help`, { stdio: [0, 1, 2] });
|
|
507
|
-
};
|
|
508
|
-
|
|
509
435
|
/**
|
|
510
436
|
* Migration for deprecated structure of apify.json to latest.
|
|
511
|
-
* @param localConfig
|
|
512
437
|
*/
|
|
438
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
513
439
|
const updateLocalConfigStructure = (localConfig) => {
|
|
514
440
|
const updatedLocalConfig = {
|
|
515
441
|
name: localConfig.name,
|
|
@@ -521,18 +447,18 @@ const updateLocalConfigStructure = (localConfig) => {
|
|
|
521
447
|
if (localConfig.version.envVars && localConfig.version.envVars.length) {
|
|
522
448
|
const env = {};
|
|
523
449
|
localConfig.version.envVars.forEach((envVar) => {
|
|
524
|
-
if (envVar.name && envVar.value)
|
|
450
|
+
if (envVar.name && envVar.value)
|
|
451
|
+
env[envVar.name] = envVar.value;
|
|
525
452
|
});
|
|
526
453
|
updatedLocalConfig.env = env;
|
|
527
454
|
}
|
|
528
455
|
return updatedLocalConfig;
|
|
529
456
|
};
|
|
530
|
-
|
|
531
457
|
/**
|
|
532
458
|
* Validates actor name, if finds issue throws error.
|
|
533
459
|
* @param actorName
|
|
534
460
|
*/
|
|
535
|
-
const validateActorName = (actorName) => {
|
|
461
|
+
export const validateActorName = (actorName) => {
|
|
536
462
|
if (!ACTOR_NAME.REGEX.test(actorName)) {
|
|
537
463
|
throw new Error('The Actor name must be a DNS hostname-friendly string (e.g. my-newest-actor).');
|
|
538
464
|
}
|
|
@@ -543,148 +469,110 @@ const validateActorName = (actorName) => {
|
|
|
543
469
|
throw new Error('The Actor name must be a maximum of 30 characters long.');
|
|
544
470
|
}
|
|
545
471
|
};
|
|
546
|
-
|
|
547
|
-
const sanitizeActorName = (actorName) => {
|
|
472
|
+
export const sanitizeActorName = (actorName) => {
|
|
548
473
|
let sanitizedName = actorName
|
|
549
474
|
.replaceAll(/[^a-zA-Z0-9-]/g, '-');
|
|
550
|
-
|
|
551
475
|
if (sanitizedName.length < ACTOR_NAME.MIN_LENGTH) {
|
|
552
476
|
sanitizedName = `${sanitizedName}-apify-actor`;
|
|
553
477
|
}
|
|
554
|
-
|
|
555
478
|
sanitizedName = sanitizedName.replaceAll(/^-+/g, '').replaceAll(/-+$/g, '');
|
|
556
|
-
|
|
557
479
|
return sanitizedName.slice(0, ACTOR_NAME.MAX_LENGTH);
|
|
558
480
|
};
|
|
559
|
-
|
|
560
|
-
const getPythonCommand = (directory) => {
|
|
481
|
+
export const getPythonCommand = (directory) => {
|
|
561
482
|
const pythonVenvPath = /^win/.test(process.platform)
|
|
562
483
|
? 'Scripts/python.exe'
|
|
563
484
|
: 'bin/python3';
|
|
564
|
-
|
|
565
485
|
let fullPythonVenvPath;
|
|
566
486
|
if (process.env.VIRTUAL_ENV) {
|
|
567
|
-
fullPythonVenvPath =
|
|
568
|
-
}
|
|
569
|
-
|
|
487
|
+
fullPythonVenvPath = join(process.env.VIRTUAL_ENV, pythonVenvPath);
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
fullPythonVenvPath = join(directory, '.venv', pythonVenvPath);
|
|
570
491
|
}
|
|
571
|
-
|
|
572
|
-
if (fs.existsSync(fullPythonVenvPath)) {
|
|
492
|
+
if (existsSync(fullPythonVenvPath)) {
|
|
573
493
|
return fullPythonVenvPath;
|
|
574
494
|
}
|
|
575
|
-
|
|
576
495
|
return /^win/.test(process.platform)
|
|
577
496
|
? 'python'
|
|
578
497
|
: 'python3';
|
|
579
498
|
};
|
|
580
|
-
|
|
581
|
-
const detectPythonVersion = (directory) => {
|
|
499
|
+
export const detectPythonVersion = (directory) => {
|
|
582
500
|
const pythonCommand = getPythonCommand(directory);
|
|
583
501
|
try {
|
|
584
502
|
const spawnResult = spawnSync(pythonCommand, ['-c', 'import platform; print(platform.python_version())'], { encoding: 'utf-8' });
|
|
585
503
|
if (!spawnResult.error && spawnResult.stdout) {
|
|
586
504
|
return spawnResult.stdout.trim();
|
|
587
505
|
}
|
|
588
|
-
|
|
506
|
+
return undefined;
|
|
507
|
+
}
|
|
508
|
+
catch {
|
|
589
509
|
return undefined;
|
|
590
510
|
}
|
|
591
511
|
};
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
return semver.satisfies(installedPythonVersion, `^${MINIMUM_SUPPORTED_PYTHON_VERSION}`);
|
|
512
|
+
export const isPythonVersionSupported = (installedPythonVersion) => {
|
|
513
|
+
return satisfies(installedPythonVersion, `^${MINIMUM_SUPPORTED_PYTHON_VERSION}`);
|
|
595
514
|
};
|
|
596
|
-
|
|
597
|
-
const detectNodeVersion = () => {
|
|
515
|
+
export const detectNodeVersion = () => {
|
|
598
516
|
try {
|
|
599
517
|
const spawnResult = spawnSync('node', ['--version'], { encoding: 'utf-8' });
|
|
600
518
|
if (!spawnResult.error && spawnResult.stdout) {
|
|
601
519
|
return spawnResult.stdout.trim().replace(/^v/, '');
|
|
602
520
|
}
|
|
603
|
-
|
|
521
|
+
return undefined;
|
|
522
|
+
}
|
|
523
|
+
catch {
|
|
604
524
|
return undefined;
|
|
605
525
|
}
|
|
606
526
|
};
|
|
607
|
-
|
|
608
|
-
const isNodeVersionSupported = (installedNodeVersion) => {
|
|
527
|
+
export const isNodeVersionSupported = (installedNodeVersion) => {
|
|
609
528
|
// SUPPORTED_NODEJS_VERSION can be a version range,
|
|
610
529
|
// we need to get the minimum supported version from that range to be able to compare them
|
|
611
|
-
const minimumSupportedNodeVersion =
|
|
612
|
-
return
|
|
530
|
+
const minimumSupportedNodeVersion = minVersion(SUPPORTED_NODEJS_VERSION);
|
|
531
|
+
return gte(installedNodeVersion, minimumSupportedNodeVersion);
|
|
613
532
|
};
|
|
614
|
-
|
|
615
|
-
const detectNpmVersion = () => {
|
|
533
|
+
export const detectNpmVersion = () => {
|
|
616
534
|
const npmCommand = getNpmCmd();
|
|
617
535
|
try {
|
|
618
536
|
const spawnResult = spawnSync(npmCommand, ['--version'], { encoding: 'utf-8' });
|
|
619
537
|
if (!spawnResult.error && spawnResult.stdout) {
|
|
620
538
|
return spawnResult.stdout.trim().replace(/^v/, '');
|
|
621
539
|
}
|
|
622
|
-
|
|
540
|
+
return undefined;
|
|
541
|
+
}
|
|
542
|
+
catch {
|
|
623
543
|
return undefined;
|
|
624
544
|
}
|
|
625
545
|
};
|
|
626
|
-
|
|
627
|
-
const
|
|
628
|
-
const
|
|
629
|
-
const isActorInNode = fs.existsSync(path.join(cwd, 'package.json'));
|
|
630
|
-
const isActorInPython = fs.existsSync(path.join(cwd, 'src/__main__.py')) || ProjectAnalyzer.getProjectType(cwd) === PROJECT_TYPES.SCRAPY;
|
|
546
|
+
export const detectLocalActorLanguage = (cwd) => {
|
|
547
|
+
const isActorInNode = existsSync(join(cwd, 'package.json'));
|
|
548
|
+
const isActorInPython = existsSync(join(cwd, 'src/__main__.py')) || ProjectAnalyzer.getProjectType(cwd) === PROJECT_TYPES.SCRAPY;
|
|
631
549
|
const result = {};
|
|
632
550
|
if (isActorInNode) {
|
|
633
551
|
result.language = LANGUAGE.NODEJS;
|
|
634
552
|
result.languageVersion = detectNodeVersion();
|
|
635
|
-
}
|
|
553
|
+
}
|
|
554
|
+
else if (isActorInPython) {
|
|
636
555
|
result.language = LANGUAGE.PYTHON;
|
|
637
556
|
result.languageVersion = detectPythonVersion(cwd);
|
|
638
|
-
}
|
|
557
|
+
}
|
|
558
|
+
else {
|
|
639
559
|
result.language = LANGUAGE.UNKNOWN;
|
|
640
560
|
}
|
|
641
561
|
return result;
|
|
642
562
|
};
|
|
643
|
-
|
|
644
|
-
const downloadAndUnzip = async ({ url, pathTo }) => {
|
|
563
|
+
export const downloadAndUnzip = async ({ url, pathTo }) => {
|
|
645
564
|
const zipStream = await httpsGet(url);
|
|
646
565
|
const chunks = [];
|
|
647
566
|
zipStream.on('data', (chunk) => chunks.push(chunk));
|
|
648
|
-
await
|
|
567
|
+
await finished(zipStream);
|
|
649
568
|
const zip = new AdmZip(Buffer.concat(chunks));
|
|
650
569
|
zip.extractAllTo(pathTo, true);
|
|
651
570
|
};
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
setLocalEnv,
|
|
659
|
-
argsToCamelCase,
|
|
660
|
-
getLoggedClient,
|
|
661
|
-
createActZip,
|
|
662
|
-
getLocalUserInfo,
|
|
663
|
-
getLocalConfigOrThrow,
|
|
664
|
-
getLocalInput,
|
|
665
|
-
purgeDefaultQueue,
|
|
666
|
-
purgeDefaultDataset,
|
|
667
|
-
purgeDefaultKeyValueStore,
|
|
668
|
-
outputJobLog,
|
|
669
|
-
getLocalKeyValueStorePath,
|
|
670
|
-
getLocalDatasetPath,
|
|
671
|
-
getLocalRequestQueuePath,
|
|
672
|
-
getNpmCmd,
|
|
673
|
-
checkIfStorageIsEmpty,
|
|
674
|
-
getLocalStorageDir,
|
|
675
|
-
showHelpForCommand,
|
|
676
|
-
getActorLocalFilePaths,
|
|
677
|
-
createSourceFiles,
|
|
678
|
-
validateActorName,
|
|
679
|
-
getJsonFileContent,
|
|
680
|
-
getApifyClientOptions,
|
|
681
|
-
detectPythonVersion,
|
|
682
|
-
isPythonVersionSupported,
|
|
683
|
-
getPythonCommand,
|
|
684
|
-
detectNodeVersion,
|
|
685
|
-
isNodeVersionSupported,
|
|
686
|
-
detectNpmVersion,
|
|
687
|
-
detectLocalActorLanguage,
|
|
688
|
-
downloadAndUnzip,
|
|
689
|
-
sanitizeActorName,
|
|
571
|
+
/**
|
|
572
|
+
* Ensures the Apify directory exists, as well as nested folders (for tests)
|
|
573
|
+
*/
|
|
574
|
+
export const ensureApifyDirectory = (file) => {
|
|
575
|
+
const path = dirname(file);
|
|
576
|
+
mkdirSync(path, { recursive: true });
|
|
690
577
|
};
|
|
578
|
+
//# sourceMappingURL=utils.js.map
|