@learnpack/learnpack 2.1.43 → 2.1.45
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 +10 -10
- package/lib/commands/start.js +12 -43
- package/lib/managers/config/index.js +1 -2
- package/lib/utils/checkNotInstalled.d.ts +7 -1
- package/lib/utils/checkNotInstalled.js +156 -16
- package/lib/utils/console.d.ts +1 -1
- package/lib/utils/console.js +7 -7
- package/oclif.manifest.json +1 -1
- package/package.json +3 -2
- package/src/commands/start.ts +17 -41
- package/src/managers/config/exercise.ts +311 -311
- package/src/managers/config/index.ts +455 -455
- package/src/models/config.ts +91 -91
- package/src/models/socket.ts +59 -59
- package/src/utils/checkNotInstalled.ts +228 -17
- package/src/utils/console.ts +24 -24
package/src/models/config.ts
CHANGED
@@ -1,91 +1,91 @@
|
|
1
|
-
import { IExercise } from "./exercise-obj"
|
2
|
-
import { TTelemetryUrls } from "../managers/telemetry"
|
3
|
-
|
4
|
-
export type TGrading = "isolated" | "incremental" | "no-grading";
|
5
|
-
|
6
|
-
export type TMode = "preview" | "extension";
|
7
|
-
|
8
|
-
export type TConfigAction =
|
9
|
-
| "test"
|
10
|
-
| "build"
|
11
|
-
| "tutorial"
|
12
|
-
| "reset"
|
13
|
-
| "generate";
|
14
|
-
|
15
|
-
export type TConfigObjAttributes = "config" | "exercises" | "grading";
|
16
|
-
|
17
|
-
export type TCompiler =
|
18
|
-
| "webpack"
|
19
|
-
| "vanillajs"
|
20
|
-
| "react"
|
21
|
-
| "html"
|
22
|
-
| "node"
|
23
|
-
| "python"
|
24
|
-
| "css";
|
25
|
-
|
26
|
-
export interface IConfigPath {
|
27
|
-
base: string;
|
28
|
-
}
|
29
|
-
|
30
|
-
type TAgent = "vscode" | "os";
|
31
|
-
|
32
|
-
export interface IEditor {
|
33
|
-
mode?: TMode;
|
34
|
-
version: string;
|
35
|
-
agent?: TAgent;
|
36
|
-
}
|
37
|
-
|
38
|
-
export interface TEntries {
|
39
|
-
python3?: string;
|
40
|
-
html?: string;
|
41
|
-
node?: string;
|
42
|
-
react?: string;
|
43
|
-
java?: string;
|
44
|
-
}
|
45
|
-
|
46
|
-
export interface IConfig {
|
47
|
-
os: string;
|
48
|
-
port?: string;
|
49
|
-
repository?: string;
|
50
|
-
description?: string;
|
51
|
-
slug?: string;
|
52
|
-
dirPath: string;
|
53
|
-
preview?: string; // Picture thumbnail
|
54
|
-
entries: TEntries;
|
55
|
-
grading: TGrading;
|
56
|
-
configPath: string;
|
57
|
-
translations: Array<string>;
|
58
|
-
outputPath?: string;
|
59
|
-
editor: IEditor;
|
60
|
-
language: string;
|
61
|
-
title: string;
|
62
|
-
duration: number;
|
63
|
-
difficulty?: string;
|
64
|
-
exercisesPath: string;
|
65
|
-
disableGrading: boolean; // TODO: Deprecate
|
66
|
-
actions: Array<string>; // TODO: Deprecate
|
67
|
-
autoPlay: boolean;
|
68
|
-
projectType?: string;
|
69
|
-
// TODO: nameExerciseValidation
|
70
|
-
contact?: string;
|
71
|
-
disabledActions?: Array<TConfigAction>;
|
72
|
-
compiler: TCompiler;
|
73
|
-
compilers: Array<TCompiler>;
|
74
|
-
publicPath: string;
|
75
|
-
publicUrl?: string;
|
76
|
-
bugsLink?: string;
|
77
|
-
videoSolutions?: boolean;
|
78
|
-
skills: Array<string>;
|
79
|
-
telemetry?: TTelemetryUrls;
|
80
|
-
runHook: (...agrs: Array<any>) => void;
|
81
|
-
testingFinishedCallback: (arg: any | undefined) => void;
|
82
|
-
}
|
83
|
-
|
84
|
-
export interface IConfigObj {
|
85
|
-
session?: number;
|
86
|
-
currentExercise?: any;
|
87
|
-
config?: IConfig;
|
88
|
-
exercises?: Array<IExercise>;
|
89
|
-
confPath?: IConfigPath;
|
90
|
-
address?: string; // Maybe
|
91
|
-
}
|
1
|
+
import { IExercise } from "./exercise-obj"
|
2
|
+
import { TTelemetryUrls } from "../managers/telemetry"
|
3
|
+
|
4
|
+
export type TGrading = "isolated" | "incremental" | "no-grading";
|
5
|
+
|
6
|
+
export type TMode = "preview" | "extension";
|
7
|
+
|
8
|
+
export type TConfigAction =
|
9
|
+
| "test"
|
10
|
+
| "build"
|
11
|
+
| "tutorial"
|
12
|
+
| "reset"
|
13
|
+
| "generate";
|
14
|
+
|
15
|
+
export type TConfigObjAttributes = "config" | "exercises" | "grading";
|
16
|
+
|
17
|
+
export type TCompiler =
|
18
|
+
| "webpack"
|
19
|
+
| "vanillajs"
|
20
|
+
| "react"
|
21
|
+
| "html"
|
22
|
+
| "node"
|
23
|
+
| "python"
|
24
|
+
| "css";
|
25
|
+
|
26
|
+
export interface IConfigPath {
|
27
|
+
base: string;
|
28
|
+
}
|
29
|
+
|
30
|
+
type TAgent = "vscode" | "os";
|
31
|
+
|
32
|
+
export interface IEditor {
|
33
|
+
mode?: TMode;
|
34
|
+
version: string;
|
35
|
+
agent?: TAgent;
|
36
|
+
}
|
37
|
+
|
38
|
+
export interface TEntries {
|
39
|
+
python3?: string;
|
40
|
+
html?: string;
|
41
|
+
node?: string;
|
42
|
+
react?: string;
|
43
|
+
java?: string;
|
44
|
+
}
|
45
|
+
|
46
|
+
export interface IConfig {
|
47
|
+
os: string;
|
48
|
+
port?: string;
|
49
|
+
repository?: string;
|
50
|
+
description?: string;
|
51
|
+
slug?: string;
|
52
|
+
dirPath: string;
|
53
|
+
preview?: string; // Picture thumbnail
|
54
|
+
entries: TEntries;
|
55
|
+
grading: TGrading;
|
56
|
+
configPath: string;
|
57
|
+
translations: Array<string>;
|
58
|
+
outputPath?: string;
|
59
|
+
editor: IEditor;
|
60
|
+
language: string;
|
61
|
+
title: string;
|
62
|
+
duration: number;
|
63
|
+
difficulty?: string;
|
64
|
+
exercisesPath: string;
|
65
|
+
disableGrading: boolean; // TODO: Deprecate
|
66
|
+
actions: Array<string>; // TODO: Deprecate
|
67
|
+
autoPlay: boolean;
|
68
|
+
projectType?: string;
|
69
|
+
// TODO: nameExerciseValidation
|
70
|
+
contact?: string;
|
71
|
+
disabledActions?: Array<TConfigAction>;
|
72
|
+
compiler: TCompiler;
|
73
|
+
compilers: Array<TCompiler>;
|
74
|
+
publicPath: string;
|
75
|
+
publicUrl?: string;
|
76
|
+
bugsLink?: string;
|
77
|
+
videoSolutions?: boolean;
|
78
|
+
skills: Array<string>;
|
79
|
+
telemetry?: TTelemetryUrls;
|
80
|
+
runHook: (...agrs: Array<any>) => void;
|
81
|
+
testingFinishedCallback: (arg: any | undefined) => void;
|
82
|
+
}
|
83
|
+
|
84
|
+
export interface IConfigObj {
|
85
|
+
session?: number;
|
86
|
+
currentExercise?: any;
|
87
|
+
config?: IConfig;
|
88
|
+
exercises?: Array<IExercise>;
|
89
|
+
confPath?: IConfigPath;
|
90
|
+
address?: string; // Maybe
|
91
|
+
}
|
package/src/models/socket.ts
CHANGED
@@ -1,59 +1,59 @@
|
|
1
|
-
import { IConfig } from "./config"
|
2
|
-
import { Server } from "socket.io"
|
3
|
-
import { DefaultEventsMap } from "socket.io/dist/typed-events"
|
4
|
-
import { TAction, ICallback } from "./action"
|
5
|
-
import { TStatus } from "./status"
|
6
|
-
|
7
|
-
export type TPossibleActions =
|
8
|
-
| "build"
|
9
|
-
| "test"
|
10
|
-
| "reset"
|
11
|
-
| "tutorial"
|
12
|
-
| "generate";
|
13
|
-
|
14
|
-
export interface ISocket {
|
15
|
-
socket: Server<
|
16
|
-
DefaultEventsMap,
|
17
|
-
DefaultEventsMap,
|
18
|
-
DefaultEventsMap,
|
19
|
-
any
|
20
|
-
> | null;
|
21
|
-
config: IConfig | null;
|
22
|
-
allowedActions: Array<TPossibleActions>;
|
23
|
-
actionCallBacks: { [key: string]: ICallback };
|
24
|
-
possibleActions: Array<TPossibleActions>;
|
25
|
-
isTestingEnvironment: boolean;
|
26
|
-
addAllowed: (actions: any) => void;
|
27
|
-
removeAllowed: (actions: any) => void;
|
28
|
-
start: (config: IConfig, server: any, isTestingEnvironment: boolean) => void;
|
29
|
-
on: (action: any, callBack: any) => void;
|
30
|
-
clean: (_: string, logs: Array<any>) => void;
|
31
|
-
complete: () => void;
|
32
|
-
ask: (questions: Array<string>) => void;
|
33
|
-
reload: (files: Array<string> | null, exercises: Array<string>) => void;
|
34
|
-
openWindow: (id: string) => void;
|
35
|
-
log: (
|
36
|
-
status: TStatus,
|
37
|
-
messages?: string | Array<string>,
|
38
|
-
report?: Array<string>,
|
39
|
-
data?: any
|
40
|
-
) => void;
|
41
|
-
emit: (
|
42
|
-
action: TAction,
|
43
|
-
status: TStatus | string,
|
44
|
-
logs: string | Array<string>,
|
45
|
-
inputs?: Array<string>,
|
46
|
-
report?: Array<string>,
|
47
|
-
data?: any
|
48
|
-
) => void;
|
49
|
-
ready: (message: string) => void;
|
50
|
-
error: (type: any, stdout: string) => void;
|
51
|
-
fatal: (msg: string) => void;
|
52
|
-
success: (type: any, stdout: string) => void;
|
53
|
-
onTestingFinished: (obj: any) => void;
|
54
|
-
}
|
55
|
-
|
56
|
-
export type TOpenWindowData = {
|
57
|
-
url: string;
|
58
|
-
exerciseSlug: string;
|
59
|
-
};
|
1
|
+
import { IConfig } from "./config"
|
2
|
+
import { Server } from "socket.io"
|
3
|
+
import { DefaultEventsMap } from "socket.io/dist/typed-events"
|
4
|
+
import { TAction, ICallback } from "./action"
|
5
|
+
import { TStatus } from "./status"
|
6
|
+
|
7
|
+
export type TPossibleActions =
|
8
|
+
| "build"
|
9
|
+
| "test"
|
10
|
+
| "reset"
|
11
|
+
| "tutorial"
|
12
|
+
| "generate";
|
13
|
+
|
14
|
+
export interface ISocket {
|
15
|
+
socket: Server<
|
16
|
+
DefaultEventsMap,
|
17
|
+
DefaultEventsMap,
|
18
|
+
DefaultEventsMap,
|
19
|
+
any
|
20
|
+
> | null;
|
21
|
+
config: IConfig | null;
|
22
|
+
allowedActions: Array<TPossibleActions>;
|
23
|
+
actionCallBacks: { [key: string]: ICallback };
|
24
|
+
possibleActions: Array<TPossibleActions>;
|
25
|
+
isTestingEnvironment: boolean;
|
26
|
+
addAllowed: (actions: any) => void;
|
27
|
+
removeAllowed: (actions: any) => void;
|
28
|
+
start: (config: IConfig, server: any, isTestingEnvironment: boolean) => void;
|
29
|
+
on: (action: any, callBack: any) => void;
|
30
|
+
clean: (_: string, logs: Array<any>) => void;
|
31
|
+
complete: () => void;
|
32
|
+
ask: (questions: Array<string>) => void;
|
33
|
+
reload: (files: Array<string> | null, exercises: Array<string>) => void;
|
34
|
+
openWindow: (id: string) => void;
|
35
|
+
log: (
|
36
|
+
status: TStatus,
|
37
|
+
messages?: string | Array<string>,
|
38
|
+
report?: Array<string>,
|
39
|
+
data?: any
|
40
|
+
) => void;
|
41
|
+
emit: (
|
42
|
+
action: TAction,
|
43
|
+
status: TStatus | string,
|
44
|
+
logs: string | Array<string>,
|
45
|
+
inputs?: Array<string>,
|
46
|
+
report?: Array<string>,
|
47
|
+
data?: any
|
48
|
+
) => void;
|
49
|
+
ready: (message: string) => void;
|
50
|
+
error: (type: any, stdout: string) => void;
|
51
|
+
fatal: (msg: string) => void;
|
52
|
+
success: (type: any, stdout: string) => void;
|
53
|
+
onTestingFinished: (obj: any) => void;
|
54
|
+
}
|
55
|
+
|
56
|
+
export type TOpenWindowData = {
|
57
|
+
url: string;
|
58
|
+
exerciseSlug: string;
|
59
|
+
};
|
@@ -1,42 +1,253 @@
|
|
1
1
|
import { IExercise } from "../models/exercise-obj"
|
2
|
-
|
2
|
+
import { promisify } from "util"
|
3
|
+
import { exec as execCallback } from "child_process"
|
4
|
+
const exec = promisify(execCallback)
|
5
|
+
|
6
|
+
import { cli } from "cli-ux"
|
7
|
+
import Console from "./console"
|
8
|
+
import { TGrading } from "../models/config"
|
9
|
+
|
10
|
+
type TNeededPlugins = {
|
11
|
+
needed: string[];
|
12
|
+
notInstalled: string[];
|
13
|
+
};
|
14
|
+
type TPackageManager = "npm" | "pip";
|
15
|
+
|
16
|
+
export const checkNotInstalledPlugins = async (
|
3
17
|
exercises: IExercise[],
|
4
|
-
installedPlugins: string[]
|
5
|
-
|
18
|
+
installedPlugins: string[],
|
19
|
+
command: any
|
20
|
+
): Promise<TNeededPlugins> => {
|
21
|
+
Console.info("Checking needed plugins...")
|
6
22
|
const usefulExtensions = new Set(["py", "js", "jsx", "html"])
|
7
23
|
const foundExtensions: string[] = []
|
24
|
+
const testingExtensions = []
|
25
|
+
const neededPlugins: string[] = []
|
26
|
+
let someExerciseWithOnlyTestFile = false // I will suppose that there are not exercises with only readme and test files
|
8
27
|
|
28
|
+
// See the extensions of the files that are not tests files
|
9
29
|
for (const e of exercises) {
|
10
|
-
|
30
|
+
const notReadmeFiles = e.files.filter(
|
31
|
+
f => !f.name.toLowerCase().includes("readme")
|
32
|
+
)
|
33
|
+
|
34
|
+
if (!someExerciseWithOnlyTestFile) {
|
35
|
+
someExerciseWithOnlyTestFile = notReadmeFiles.every(f =>
|
36
|
+
f.name.includes("test")
|
37
|
+
)
|
38
|
+
}
|
39
|
+
|
40
|
+
for (const f of notReadmeFiles) {
|
41
|
+
// There are some courses with only test files in js and grading: incremental
|
42
|
+
// TODO: We should know in the incremental exercises which compilers are needed
|
43
|
+
|
11
44
|
const ext = f.name.split(".").pop()
|
45
|
+
if (f.name.includes("test")) {
|
46
|
+
testingExtensions.push(ext)
|
47
|
+
continue
|
48
|
+
}
|
49
|
+
|
12
50
|
if (ext && usefulExtensions.has(ext) && !foundExtensions.includes(ext)) {
|
13
51
|
foundExtensions.push(ext)
|
14
52
|
}
|
15
53
|
}
|
16
54
|
}
|
17
55
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
56
|
+
if (foundExtensions.length === 0)
|
57
|
+
return {
|
58
|
+
needed: [],
|
59
|
+
notInstalled: [],
|
22
60
|
}
|
23
61
|
|
24
|
-
|
25
|
-
|
62
|
+
if (foundExtensions.includes("html") && foundExtensions.includes("js")) {
|
63
|
+
neededPlugins.push("@learnpack/dom")
|
64
|
+
}
|
65
|
+
|
66
|
+
if (foundExtensions.includes("html") && !foundExtensions.includes("js")) {
|
67
|
+
neededPlugins.push("@learnpack/html")
|
68
|
+
}
|
69
|
+
|
70
|
+
if (foundExtensions.includes("jsx")) {
|
71
|
+
neededPlugins.push("@learnpack/react")
|
72
|
+
}
|
73
|
+
|
74
|
+
if (foundExtensions.includes("py") || testingExtensions.includes("py")) {
|
75
|
+
neededPlugins.push("@learnpack/python")
|
76
|
+
}
|
77
|
+
|
78
|
+
if (
|
79
|
+
(foundExtensions.includes("js") && !foundExtensions.includes("html")) ||
|
80
|
+
(testingExtensions.includes("js") && someExerciseWithOnlyTestFile)
|
81
|
+
) {
|
82
|
+
neededPlugins.push("@learnpack/node")
|
83
|
+
}
|
84
|
+
|
85
|
+
const notInstalled = neededPlugins.filter(
|
86
|
+
item => !installedPlugins.includes(item)
|
87
|
+
)
|
88
|
+
|
89
|
+
if (notInstalled.length > 0) {
|
90
|
+
Console.error(
|
91
|
+
"These plugins are not installed but required: ",
|
92
|
+
notInstalled
|
93
|
+
)
|
94
|
+
const confirmInstall = await cli.confirm(
|
95
|
+
"Do you want to install the needed plugins? (y/n)"
|
96
|
+
)
|
97
|
+
if (confirmInstall) {
|
98
|
+
Console.info("Installing the needed plugins...")
|
99
|
+
for await (const p of notInstalled) {
|
100
|
+
await command.config.runCommand(`plugins:install`, [p])
|
101
|
+
Console.log(`Plugin ${p} installed`)
|
102
|
+
}
|
103
|
+
|
104
|
+
Console.log(
|
105
|
+
"All needed plugins installed, please restart LearnPack to load them."
|
106
|
+
)
|
107
|
+
Console.info("Run: $ learnpack start")
|
108
|
+
command.exit(0)
|
109
|
+
} else {
|
110
|
+
Console.error(
|
111
|
+
"You need to install the plugins to complete this exercise"
|
112
|
+
)
|
113
|
+
Console.info(
|
114
|
+
"To install the plugins run each of the following commands: "
|
115
|
+
)
|
116
|
+
for (const p of notInstalled) {
|
117
|
+
Console.log(`learnpack plugins:install ${p}`)
|
118
|
+
}
|
119
|
+
|
120
|
+
command.exit(1)
|
26
121
|
}
|
122
|
+
}
|
27
123
|
|
28
|
-
|
29
|
-
|
124
|
+
return {
|
125
|
+
needed: neededPlugins,
|
126
|
+
notInstalled,
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
function includesAll(baseString: string, elementsArray: string[]) {
|
131
|
+
return elementsArray.every(element => baseString.includes(element))
|
132
|
+
}
|
133
|
+
|
134
|
+
const installDependencies = async (
|
135
|
+
deps: string[],
|
136
|
+
packageManager: TPackageManager
|
137
|
+
) => {
|
138
|
+
let command = ""
|
139
|
+
if (packageManager === "npm") {
|
140
|
+
command = `npm install -g ${deps.join(" ")}`
|
141
|
+
} else if (packageManager === "pip") {
|
142
|
+
command = `pip install ${deps.join(" ")}`
|
143
|
+
}
|
144
|
+
|
145
|
+
const { stdout, stderr } = await exec(command)
|
146
|
+
if (stderr && (stderr.includes("npm ERR!") || stderr.includes("Traceback"))) {
|
147
|
+
Console.error(`Error executing ${command}.`)
|
148
|
+
Console.error(stderr)
|
149
|
+
return
|
150
|
+
}
|
151
|
+
|
152
|
+
Console.info(`Dependencies ${deps.join(" ")} installed...`)
|
153
|
+
return true
|
154
|
+
}
|
155
|
+
|
156
|
+
export const checkNotInstalledDependencies = async (
|
157
|
+
neededPlugins: string[]
|
158
|
+
) => {
|
159
|
+
Console.info("Checking needed dependencies...")
|
160
|
+
const jsPluginsDependencies = [
|
161
|
+
"jest@29.7.0",
|
162
|
+
"jest-environment-jsdom@29.7.0",
|
163
|
+
]
|
164
|
+
const pyPluginsDependencies = ["pytest==6.2.5", "pytest-testdox", "mock"]
|
165
|
+
|
166
|
+
const npmLsCommand = "npm ls jest jest-environment-jsdom -g"
|
167
|
+
|
168
|
+
let pytestNeeded = false
|
169
|
+
let jestNeeded = false
|
170
|
+
|
171
|
+
if (
|
172
|
+
neededPlugins.includes("@learnpack/dom") ||
|
173
|
+
neededPlugins.includes("@learnpack/html") ||
|
174
|
+
neededPlugins.includes("@learnpack/react") ||
|
175
|
+
neededPlugins.includes("@learnpack/node")
|
176
|
+
) {
|
177
|
+
jestNeeded = true
|
178
|
+
}
|
179
|
+
|
180
|
+
if ("@learnpack/python" in neededPlugins) {
|
181
|
+
pytestNeeded = true
|
182
|
+
}
|
183
|
+
|
184
|
+
if (jestNeeded) {
|
185
|
+
const { stdout, stderr } = await exec(
|
186
|
+
"npm ls jest jest-environment-jsdom -g"
|
187
|
+
)
|
188
|
+
if (stderr) {
|
189
|
+
Console.error(`Error executing ${npmLsCommand}. Use debug for more info`)
|
190
|
+
Console.debug(stderr)
|
191
|
+
return false
|
30
192
|
}
|
31
193
|
|
32
|
-
if (
|
33
|
-
|
194
|
+
if (includesAll(stdout, jsPluginsDependencies))
|
195
|
+
return true
|
196
|
+
|
197
|
+
Console.error("The jest dependencies are not installed")
|
198
|
+
const confirmInstall = await cli.confirm(
|
199
|
+
"Do you want to install the needed dependencies? (y/n)"
|
200
|
+
)
|
201
|
+
if (!confirmInstall) {
|
202
|
+
Console.error(
|
203
|
+
`The exercises can't be tested without the following dependencies: ${jsPluginsDependencies.join(
|
204
|
+
", "
|
205
|
+
)}`
|
206
|
+
)
|
207
|
+
Console.info(
|
208
|
+
`Please install them and try again. Run the following command to install them: \nnpm install -g ${jsPluginsDependencies.join(
|
209
|
+
" "
|
210
|
+
)}`
|
211
|
+
)
|
212
|
+
return false
|
34
213
|
}
|
35
214
|
|
36
|
-
|
37
|
-
|
215
|
+
Console.log("Installing jest dependencies...")
|
216
|
+
await installDependencies(jsPluginsDependencies, "npm")
|
217
|
+
}
|
218
|
+
|
219
|
+
if (pytestNeeded) {
|
220
|
+
const { stdout, stderr } = await exec("pip list")
|
221
|
+
if (stderr) {
|
222
|
+
Console.error(`Error executing pip list. Use debug for more info`)
|
223
|
+
Console.debug(stderr)
|
224
|
+
return
|
225
|
+
}
|
226
|
+
|
227
|
+
if (includesAll(stdout, pyPluginsDependencies))
|
228
|
+
return true
|
229
|
+
|
230
|
+
Console.error("The pytest dependencies are not installed")
|
231
|
+
const confirmInstall = await cli.confirm(
|
232
|
+
"Do you want to install the needed dependencies? (y/n)"
|
233
|
+
)
|
234
|
+
if (!confirmInstall) {
|
235
|
+
Console.error(
|
236
|
+
`The exercises can't be tested without the following dependencies: ${pyPluginsDependencies.join(
|
237
|
+
", "
|
238
|
+
)}`
|
239
|
+
)
|
240
|
+
Console.info(
|
241
|
+
`Please install them and try again. Run the following command to install them: \npip install ${pyPluginsDependencies.join(
|
242
|
+
" "
|
243
|
+
)}`
|
244
|
+
)
|
245
|
+
return false
|
38
246
|
}
|
247
|
+
|
248
|
+
Console.log("Installing pytest dependencies...")
|
249
|
+
await installDependencies(pyPluginsDependencies, "pip")
|
39
250
|
}
|
40
251
|
|
41
|
-
return
|
252
|
+
return true
|
42
253
|
}
|
package/src/utils/console.ts
CHANGED
@@ -1,24 +1,24 @@
|
|
1
|
-
import * as chalk from
|
2
|
-
|
3
|
-
export default {
|
4
|
-
// _debug: true,
|
5
|
-
_debug: process.env.DEBUG ===
|
6
|
-
startDebug: function () {
|
7
|
-
this._debug = true
|
8
|
-
},
|
9
|
-
log: (msg: string | Array<string>, ...args: Array<any>) =>
|
10
|
-
console.log(chalk.gray(msg), ...args),
|
11
|
-
error: (msg: string, ...args: Array<any>) =>
|
12
|
-
console.log(chalk.red(
|
13
|
-
success: (msg: string, ...args: Array<any>) =>
|
14
|
-
console.log(chalk.green(
|
15
|
-
info: (msg:
|
16
|
-
console.log(chalk.blue(
|
17
|
-
help: (msg: string) =>
|
18
|
-
console.log(`${chalk.white.bold(
|
19
|
-
debug(...args: Array<any>) {
|
20
|
-
this._debug && console.log(chalk.magentaBright(
|
21
|
-
},
|
22
|
-
warning: (msg: string) =>
|
23
|
-
console.log(`${chalk.yellow(
|
24
|
-
}
|
1
|
+
import * as chalk from "chalk"
|
2
|
+
|
3
|
+
export default {
|
4
|
+
// _debug: true,
|
5
|
+
_debug: process.env.DEBUG === "true",
|
6
|
+
startDebug: function () {
|
7
|
+
this._debug = true
|
8
|
+
},
|
9
|
+
log: (msg: string | Array<string>, ...args: Array<any>) =>
|
10
|
+
console.log(chalk.gray(msg), ...args),
|
11
|
+
error: (msg: string, ...args: Array<any>) =>
|
12
|
+
console.log(chalk.red("⨉ " + msg), ...args),
|
13
|
+
success: (msg: string, ...args: Array<any>) =>
|
14
|
+
console.log(chalk.green("✓ " + msg), ...args),
|
15
|
+
info: (msg: any, ...args: Array<any>) =>
|
16
|
+
console.log(chalk.blue("ⓘ " + msg), ...args),
|
17
|
+
help: (msg: string) =>
|
18
|
+
console.log(`${chalk.white.bold("⚠ help:")} ${chalk.white(msg)}`),
|
19
|
+
debug(...args: Array<any>) {
|
20
|
+
this._debug && console.log(chalk.magentaBright("⚠ debug: "), args)
|
21
|
+
},
|
22
|
+
warning: (msg: string) =>
|
23
|
+
console.log(`${chalk.yellow("⚠ warning:")} ${chalk.yellow(msg)}`),
|
24
|
+
}
|