@cyklang/cli 0.3.1 → 0.4.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/build/AssetCommand.js +62 -8
- package/build/Cmd.d.ts +8 -0
- package/build/Cmd.js +50 -0
- package/build/DBClient.d.ts +10 -0
- package/build/DBClient.js +32 -0
- package/build/ModuleCommand.js +41 -5
- package/build/TableCommand.js +38 -0
- package/build/UserCommand.js +8 -3
- package/package.json +1 -1
- package/src/AssetCommand.ts +67 -14
- package/src/Cmd.ts +59 -0
- package/src/DBClient.ts +35 -1
- package/src/ModuleCommand.ts +46 -5
- package/src/TableCommand.ts +41 -0
- package/src/UserCommand.ts +8 -3
- package/test/t26.output +7 -0
- package/test/t26.xml +37 -0
package/build/AssetCommand.js
CHANGED
|
@@ -42,8 +42,9 @@ class AssetCommand extends commander_1.Command {
|
|
|
42
42
|
this.description(description);
|
|
43
43
|
this.addCommand(new AssetList('list', 'list assets'));
|
|
44
44
|
this.addCommand(new AssetList('l', '(l)ist assets'));
|
|
45
|
-
this.addCommand(new
|
|
46
|
-
this.addCommand(new
|
|
45
|
+
this.addCommand(new AssetU('upload', 'upload asset content from source files to a <destination> path'));
|
|
46
|
+
this.addCommand(new AssetU('update', 'update properties of asset identified by its <id>'));
|
|
47
|
+
this.addCommand(new AssetU('u', '(u)pload assets content from sources or (u)pdate asset properties'));
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
exports.AssetCommand = AssetCommand;
|
|
@@ -51,6 +52,7 @@ class AssetList extends Cmd_1.Cmd {
|
|
|
51
52
|
constructor(name, description) {
|
|
52
53
|
super(name);
|
|
53
54
|
this.description(description)
|
|
55
|
+
.option('-d --dest <destination>', 'filter assets whose pathname begins with destination')
|
|
54
56
|
.option('-s --sort <columns>', 'sort list by column numbers (begins by 0) separated by comma')
|
|
55
57
|
.action(async (options) => { await this.commandList(options); });
|
|
56
58
|
}
|
|
@@ -60,14 +62,20 @@ class AssetList extends Cmd_1.Cmd {
|
|
|
60
62
|
if (this.dbManager === undefined)
|
|
61
63
|
throw 'dbManager undefined';
|
|
62
64
|
const dbClient = new DBClient_1.DBClient(this.dbManager);
|
|
63
|
-
dbClient.selectFromTable('List of Assets', 'cyk_asset', {
|
|
65
|
+
dbClient.selectFromTable('List of Assets', 'cyk_asset', {
|
|
66
|
+
fields: 'asset_id,asset_route,asset_auth,asset_access,asset_mimetype,asset_last_update', sort: options.sort || '1',
|
|
67
|
+
where: (options.dest ? "asset_route like '" + options.dest + "%'" : undefined)
|
|
68
|
+
});
|
|
64
69
|
}
|
|
65
70
|
catch (err) {
|
|
66
71
|
logger.error(err);
|
|
67
72
|
}
|
|
68
73
|
}
|
|
69
74
|
}
|
|
70
|
-
|
|
75
|
+
/**
|
|
76
|
+
* class AssetU
|
|
77
|
+
*/
|
|
78
|
+
class AssetU extends Cmd_1.Cmd {
|
|
71
79
|
constructor(name, description) {
|
|
72
80
|
super(name);
|
|
73
81
|
//----------------------------------------------------------------------------------------------
|
|
@@ -75,13 +83,15 @@ class AssetUpload extends Cmd_1.Cmd {
|
|
|
75
83
|
//----------------------------------------------------------------------------------------------
|
|
76
84
|
this.ignorePatterns = ['.git', 'node_modules'];
|
|
77
85
|
this.description(description)
|
|
78
|
-
.option('-
|
|
86
|
+
.option('-i --id <id>', 'asset id to update properties')
|
|
87
|
+
.option('--auth <auth_schema>', 'authentication schema : basic | token | cookie | any | none, default is none')
|
|
88
|
+
.option('--access <access>', 'access rights required')
|
|
79
89
|
.option('-d --dest <destination>', 'destination path, directory name')
|
|
80
90
|
.option('-c --clean', 'clean destination path before uploading')
|
|
81
91
|
.option('-y --yes', 'upload list is automatically confirmed')
|
|
82
92
|
.argument('[sources...]', 'local files or directories to upload as assets to the server')
|
|
83
93
|
.action(async (sources, options) => {
|
|
84
|
-
await this.
|
|
94
|
+
await this.commandU(sources, options);
|
|
85
95
|
});
|
|
86
96
|
}
|
|
87
97
|
mimetypeLookup(filename) {
|
|
@@ -94,6 +104,48 @@ class AssetUpload extends Cmd_1.Cmd {
|
|
|
94
104
|
}
|
|
95
105
|
return result;
|
|
96
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* method commandU
|
|
109
|
+
* @param sources
|
|
110
|
+
* @param options
|
|
111
|
+
*/
|
|
112
|
+
async commandU(sources, options) {
|
|
113
|
+
if (sources.length > 0) {
|
|
114
|
+
// upload
|
|
115
|
+
logger.debug('upload sources :', sources);
|
|
116
|
+
await this.commandUpload(sources, options);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
// update
|
|
120
|
+
logger.debug('update', options);
|
|
121
|
+
await this.commandUpdate(options);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* method commandUpdate
|
|
126
|
+
* @param options
|
|
127
|
+
*/
|
|
128
|
+
async commandUpdate(options) {
|
|
129
|
+
try {
|
|
130
|
+
await this.prologue(options);
|
|
131
|
+
if (this.dbManager === undefined)
|
|
132
|
+
throw 'dbManager undefined';
|
|
133
|
+
if (options.id === undefined)
|
|
134
|
+
throw '<id_or_route> of asset to update is missing';
|
|
135
|
+
const dbAsset = await this.dbManager.dbAssetExist(options.id);
|
|
136
|
+
if (dbAsset === undefined)
|
|
137
|
+
throw 'Asset ' + options.id + ' not found';
|
|
138
|
+
await this.updateAuthAccess('cyk_asset', 'assert', dbAsset.id || '', options);
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
logger.error(err);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* method commandUpload
|
|
146
|
+
* @param sources
|
|
147
|
+
* @param options
|
|
148
|
+
*/
|
|
97
149
|
async commandUpload(sources, options) {
|
|
98
150
|
try {
|
|
99
151
|
await this.prologue(options);
|
|
@@ -101,8 +153,8 @@ class AssetUpload extends Cmd_1.Cmd {
|
|
|
101
153
|
throw 'dbManager undefined';
|
|
102
154
|
if (sources.length === 0)
|
|
103
155
|
throw 'no source to upload';
|
|
104
|
-
if (options.auth && ' basic | token | any '.indexOf(options.auth) === -1) {
|
|
105
|
-
throw 'valid authentication schemas are : basic | token | any';
|
|
156
|
+
if (options.auth && ' basic | token | cookie | any | none'.indexOf(options.auth) === -1) {
|
|
157
|
+
throw 'valid authentication schemas are : basic | token | cookie | any | none';
|
|
106
158
|
}
|
|
107
159
|
logger.debug('options : ', options);
|
|
108
160
|
logger.debug('auth : ' + options.auth);
|
|
@@ -299,6 +351,8 @@ class AssetUpload extends Cmd_1.Cmd {
|
|
|
299
351
|
dbAsset.mimetype = mimetype;
|
|
300
352
|
dbAsset.route = route;
|
|
301
353
|
dbAsset.auth = auth;
|
|
354
|
+
if (dbAsset.auth === 'none')
|
|
355
|
+
dbAsset.auth = undefined;
|
|
302
356
|
// const fstat = fs.statSync(fileName)
|
|
303
357
|
dbAsset.last_update = upload.mtime;
|
|
304
358
|
// const contentBuffer = fs.readFileSync(fileName)
|
package/build/Cmd.d.ts
CHANGED
|
@@ -5,4 +5,12 @@ export declare class Cmd extends Command {
|
|
|
5
5
|
dbRemote: DBRemote | undefined;
|
|
6
6
|
constructor(name: string);
|
|
7
7
|
prologue(options: any): Promise<SigninResponse>;
|
|
8
|
+
/**
|
|
9
|
+
* method updateAuthAccess
|
|
10
|
+
* @param tableName
|
|
11
|
+
* @param prefix
|
|
12
|
+
* @param id
|
|
13
|
+
* @param options
|
|
14
|
+
*/
|
|
15
|
+
updateAuthAccess(tableName: string, prefix: string, id: string, options: any): Promise<void>;
|
|
8
16
|
}
|
package/build/Cmd.js
CHANGED
|
@@ -9,6 +9,7 @@ const commander_1 = require("commander");
|
|
|
9
9
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
10
10
|
const loglevel_1 = __importDefault(require("loglevel"));
|
|
11
11
|
const NodeCrypto_1 = require("./NodeCrypto");
|
|
12
|
+
const DBClient_1 = require("./DBClient");
|
|
12
13
|
const logger = loglevel_1.default.getLogger('Cmd.ts');
|
|
13
14
|
logger.setLevel('debug');
|
|
14
15
|
class Cmd extends commander_1.Command {
|
|
@@ -32,5 +33,54 @@ class Cmd extends commander_1.Command {
|
|
|
32
33
|
await this.dbManager.initialize();
|
|
33
34
|
return login;
|
|
34
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* method updateAuthAccess
|
|
38
|
+
* @param tableName
|
|
39
|
+
* @param prefix
|
|
40
|
+
* @param id
|
|
41
|
+
* @param options
|
|
42
|
+
*/
|
|
43
|
+
async updateAuthAccess(tableName, prefix, id, options) {
|
|
44
|
+
try {
|
|
45
|
+
let dclAuth;
|
|
46
|
+
if (options.auth) {
|
|
47
|
+
if (' basic | token | cookie | any | none | null '.indexOf(' ' + options.auth + ' ') === -1) {
|
|
48
|
+
throw 'valid authentication schemas are : basic | token | cookie | any | null';
|
|
49
|
+
}
|
|
50
|
+
dclAuth = `<string name='${prefix}_auth'>`;
|
|
51
|
+
if (' none | null '.indexOf(' ' + options.auth + ' ') === -1)
|
|
52
|
+
dclAuth += ` "${options.auth}" `;
|
|
53
|
+
else
|
|
54
|
+
dclAuth += ' null ';
|
|
55
|
+
dclAuth += "</string>";
|
|
56
|
+
}
|
|
57
|
+
let dclAccess;
|
|
58
|
+
if (options.access) {
|
|
59
|
+
dclAccess = `<string name='${prefix}_access'> `;
|
|
60
|
+
if (' null | none '.indexOf(' ' + options.access + ' ') === -1)
|
|
61
|
+
dclAccess += `"${options.access}"`;
|
|
62
|
+
else
|
|
63
|
+
dclAccess += ' null ';
|
|
64
|
+
dclAccess += "</string>";
|
|
65
|
+
}
|
|
66
|
+
const inst = `
|
|
67
|
+
<db.update table='${tableName}'>
|
|
68
|
+
<object>
|
|
69
|
+
<number name='${prefix}_id'>${id}</number>
|
|
70
|
+
${dclAuth}
|
|
71
|
+
${dclAccess ? dclAccess : ''}
|
|
72
|
+
</object>
|
|
73
|
+
</db.update>
|
|
74
|
+
`;
|
|
75
|
+
if (!this.dbManager)
|
|
76
|
+
throw 'prologue() has not been called before';
|
|
77
|
+
const dbClient = new DBClient_1.DBClient(this.dbManager);
|
|
78
|
+
dbClient.execInstructions(inst);
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
logger.error(err);
|
|
82
|
+
throw err;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
35
85
|
}
|
|
36
86
|
exports.Cmd = Cmd;
|
package/build/DBClient.d.ts
CHANGED
|
@@ -2,6 +2,16 @@ import { DBManager } from "@cyklang/core";
|
|
|
2
2
|
export declare class DBClient {
|
|
3
3
|
dbManager: DBManager;
|
|
4
4
|
constructor(dbManager: DBManager);
|
|
5
|
+
/**
|
|
6
|
+
* method execInstructions
|
|
7
|
+
* @param source
|
|
8
|
+
*/
|
|
9
|
+
execInstructions(source: string): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* method execScript
|
|
12
|
+
* @param source
|
|
13
|
+
*/
|
|
14
|
+
execScript(source: string): Promise<void>;
|
|
5
15
|
runQuery(): Promise<void>;
|
|
6
16
|
selectFromTable(title: string, tableName: string, options: {
|
|
7
17
|
fields: string;
|
package/build/DBClient.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.DBClient = void 0;
|
|
7
7
|
const core_1 = require("@cyklang/core");
|
|
8
8
|
const loglevel_1 = __importDefault(require("loglevel"));
|
|
9
|
+
const console_1 = require("./console");
|
|
9
10
|
const logger = loglevel_1.default.getLogger('DBClient.ts');
|
|
10
11
|
logger.setLevel('debug');
|
|
11
12
|
// DBManager wrapper class
|
|
@@ -13,6 +14,37 @@ class DBClient {
|
|
|
13
14
|
constructor(dbManager) {
|
|
14
15
|
this.dbManager = dbManager;
|
|
15
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* method execInstructions
|
|
19
|
+
* @param source
|
|
20
|
+
*/
|
|
21
|
+
async execInstructions(source) {
|
|
22
|
+
const script = `<?xml-model href="https://www.cyklang.net/schema/cyklang.xsd" type="application/xml" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
|
23
|
+
<module>
|
|
24
|
+
` + source + `
|
|
25
|
+
</module>`;
|
|
26
|
+
await this.execScript(script);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* method execScript
|
|
30
|
+
* @param source
|
|
31
|
+
*/
|
|
32
|
+
async execScript(source) {
|
|
33
|
+
try {
|
|
34
|
+
const script = new core_1.Script(this.dbManager.scope, '', source);
|
|
35
|
+
await script.parseInstructions();
|
|
36
|
+
await script.execute();
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
console.log(source);
|
|
40
|
+
console.log();
|
|
41
|
+
if (err instanceof core_1.XmlError) {
|
|
42
|
+
let xmlError = err;
|
|
43
|
+
(0, console_1.errorconsole)(xmlError);
|
|
44
|
+
}
|
|
45
|
+
console.log(err);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
16
48
|
async runQuery() {
|
|
17
49
|
}
|
|
18
50
|
async selectFromTable(title, tableName, options) {
|
package/build/ModuleCommand.js
CHANGED
|
@@ -38,10 +38,10 @@ class ModuleCommand extends commander_1.Command {
|
|
|
38
38
|
super(name);
|
|
39
39
|
this.description('manage modules');
|
|
40
40
|
// upload
|
|
41
|
-
this.addCommand(new
|
|
41
|
+
this.addCommand(new ModuleU('upload', `Upload local module file(s) to the database.
|
|
42
42
|
Module name is the base name of the file. If a module with the same name already exists, it will be updated.
|
|
43
43
|
Otherwise, a new module is inserted in the database. To rename a module, use option --id to indicate the module you want to rename`));
|
|
44
|
-
this.addCommand(new
|
|
44
|
+
this.addCommand(new ModuleU('u', 'shortcut for (u)pload'));
|
|
45
45
|
// download
|
|
46
46
|
this.addCommand(new ModuleDownload('download', 'download module files to the current directory'));
|
|
47
47
|
this.addCommand(new ModuleDownload('d', 'shortcut for (d)ownload'));
|
|
@@ -64,16 +64,52 @@ function getModuleDBName(filePath) {
|
|
|
64
64
|
throw 'filename ' + result + ' does not match identifier syntax';
|
|
65
65
|
return result;
|
|
66
66
|
}
|
|
67
|
-
|
|
67
|
+
/**
|
|
68
|
+
* class ModuleU
|
|
69
|
+
*/
|
|
70
|
+
class ModuleU extends Cmd_1.Cmd {
|
|
68
71
|
constructor(name, description) {
|
|
69
72
|
super(name);
|
|
70
73
|
this.description(description)
|
|
71
|
-
.option('
|
|
74
|
+
.option('--auth <auth_schema>', 'authentication schema : basic | token | cookie | any | none, default is none')
|
|
75
|
+
.option('--access <access_right>', 'access rights required')
|
|
76
|
+
.option('-i --id <id>', 'module ID to upload or update')
|
|
72
77
|
.argument('[files...]', 'local module file(s) to upload to the server')
|
|
73
78
|
.action(async (files, options) => {
|
|
74
|
-
await this.
|
|
79
|
+
await this.commandU(files, options);
|
|
75
80
|
});
|
|
76
81
|
}
|
|
82
|
+
async commandU(files, options) {
|
|
83
|
+
if (files.length > 0) {
|
|
84
|
+
await this.commandUpload(files, options);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
await this.commandUpdate(options);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* method commandUpdate
|
|
92
|
+
* @param options
|
|
93
|
+
*/
|
|
94
|
+
async commandUpdate(options) {
|
|
95
|
+
try {
|
|
96
|
+
await this.prologue(options);
|
|
97
|
+
if (this.dbManager === undefined)
|
|
98
|
+
throw 'dbManager undefined';
|
|
99
|
+
if (options.id === undefined)
|
|
100
|
+
throw '<id_or_route> of module to update is missing';
|
|
101
|
+
const dbModule = await this.dbManager.getModule(options.id);
|
|
102
|
+
await this.updateAuthAccess('cyk_module', 'module', dbModule.id || '', options);
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
logger.error(err);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* method commandUpload
|
|
110
|
+
* @param files
|
|
111
|
+
* @param options
|
|
112
|
+
*/
|
|
77
113
|
async commandUpload(files, options) {
|
|
78
114
|
try {
|
|
79
115
|
await this.prologue(options);
|
package/build/TableCommand.js
CHANGED
|
@@ -43,9 +43,47 @@ class TableCommand extends commander_1.Command {
|
|
|
43
43
|
this.addCommand(new TableList('l', '(l)ist database tables'));
|
|
44
44
|
this.addCommand(new TableData('data', 'table (d)ata'));
|
|
45
45
|
this.addCommand(new TableData('d', 'table (d)ata'));
|
|
46
|
+
this.addCommand(new TableUpdate('update', 'update table properties'));
|
|
47
|
+
this.addCommand(new TableUpdate('u', 'shortcut for (u)pdate table properties'));
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
50
|
exports.TableCommand = TableCommand;
|
|
51
|
+
/**
|
|
52
|
+
* class TableUpdate
|
|
53
|
+
*/
|
|
54
|
+
class TableUpdate extends Cmd_1.Cmd {
|
|
55
|
+
/**
|
|
56
|
+
*
|
|
57
|
+
* @param name
|
|
58
|
+
* @param description
|
|
59
|
+
*/
|
|
60
|
+
constructor(name, description) {
|
|
61
|
+
super(name);
|
|
62
|
+
this.description(description)
|
|
63
|
+
.option('-n --name <table_name>', 'name of the table whose properties are to be changed')
|
|
64
|
+
.option('--auth <auth_schema>', 'authentication schema : basic | token | cookie | any | none, default is none')
|
|
65
|
+
.option('--access <access>', 'access rights required')
|
|
66
|
+
.action(async (options) => {
|
|
67
|
+
await this.commandUpdate(options);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
async commandUpdate(options) {
|
|
71
|
+
try {
|
|
72
|
+
await this.prologue(options);
|
|
73
|
+
if (this.dbManager === undefined)
|
|
74
|
+
throw 'dbManager undefined';
|
|
75
|
+
if (!options.name)
|
|
76
|
+
throw '<table_name> is missing';
|
|
77
|
+
const dbTable = await this.dbManager.dbTableExist(options.name);
|
|
78
|
+
if (!dbTable)
|
|
79
|
+
throw 'Table ' + options.name + ' not found';
|
|
80
|
+
await this.updateAuthAccess('cyk_table', 'table', dbTable.id || '', options);
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
logger.error(err);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
49
87
|
class TableExportCmd extends Cmd_1.Cmd {
|
|
50
88
|
constructor() {
|
|
51
89
|
super('export');
|
package/build/UserCommand.js
CHANGED
|
@@ -22,6 +22,7 @@ class UserCommand extends commander_1.Command {
|
|
|
22
22
|
this.addCommand(new UserUpdateCmd('u', 'shortcut for (u)pdate'));
|
|
23
23
|
this.addCommand(new UserDeleteCmd('delete', 'delete user by id and name. Both options are mandatory to avoid typing error'));
|
|
24
24
|
this.addCommand(new UserPasswdCmd('passwd', 'change user password'));
|
|
25
|
+
this.addCommand(new UserPasswdCmd('p', 'shortcut for (p)asswd'));
|
|
25
26
|
this.addCommand(new UserListCmd('list', 'list users'));
|
|
26
27
|
this.addCommand(new UserListCmd('l', 'shortcut for (l)ist'));
|
|
27
28
|
}
|
|
@@ -33,7 +34,7 @@ class UserAddCmd extends Cmd_1.Cmd {
|
|
|
33
34
|
this.description(description)
|
|
34
35
|
.requiredOption('-n --name <name>', 'user name')
|
|
35
36
|
.option('-e --email <email>', 'user email address')
|
|
36
|
-
.option('-p --
|
|
37
|
+
.option('-p --password <password>', 'initial password')
|
|
37
38
|
.option('-a --access <acl>', 'access control list')
|
|
38
39
|
.option('-m --module <module_name>', 'module to launch by default')
|
|
39
40
|
.option('-d --disable', 'user not abled to connect')
|
|
@@ -56,7 +57,11 @@ class UserAddCmd extends Cmd_1.Cmd {
|
|
|
56
57
|
if (this.dbManager === undefined)
|
|
57
58
|
throw 'dbManager undefined';
|
|
58
59
|
const result = await this.dbManager.dbUserInsert(dbUser);
|
|
59
|
-
logger.debug(result);
|
|
60
|
+
logger.debug('ID', result);
|
|
61
|
+
if (dbUser.password) {
|
|
62
|
+
await this.dbManager.dbUserPasswd(result, dbUser.password);
|
|
63
|
+
logger.info('password changed for user ' + dbUser.name);
|
|
64
|
+
}
|
|
60
65
|
}
|
|
61
66
|
catch (err) {
|
|
62
67
|
logger.error(err);
|
|
@@ -173,7 +178,7 @@ class UserDeleteCmd extends Cmd_1.Cmd {
|
|
|
173
178
|
}
|
|
174
179
|
class UserPasswdCmd extends Cmd_1.Cmd {
|
|
175
180
|
constructor(name, description) {
|
|
176
|
-
super(
|
|
181
|
+
super(name);
|
|
177
182
|
this.description(description)
|
|
178
183
|
.requiredOption('-i --id <id>', 'user ID')
|
|
179
184
|
.requiredOption('-n --name <name>', 'user name')
|
package/package.json
CHANGED
package/src/AssetCommand.ts
CHANGED
|
@@ -19,8 +19,9 @@ export class AssetCommand extends Command {
|
|
|
19
19
|
this.description(description)
|
|
20
20
|
this.addCommand(new AssetList('list', 'list assets'))
|
|
21
21
|
this.addCommand(new AssetList('l', '(l)ist assets'))
|
|
22
|
-
this.addCommand(new
|
|
23
|
-
this.addCommand(new
|
|
22
|
+
this.addCommand(new AssetU('upload', 'upload asset content from source files to a <destination> path'))
|
|
23
|
+
this.addCommand(new AssetU('update', 'update properties of asset identified by its <id>'))
|
|
24
|
+
this.addCommand(new AssetU('u', '(u)pload assets content from sources or (u)pdate asset properties'))
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
27
|
|
|
@@ -28,6 +29,7 @@ class AssetList extends Cmd {
|
|
|
28
29
|
constructor(name: string, description: string) {
|
|
29
30
|
super(name)
|
|
30
31
|
this.description(description)
|
|
32
|
+
.option('-d --dest <destination>', 'filter assets whose pathname begins with destination')
|
|
31
33
|
.option('-s --sort <columns>', 'sort list by column numbers (begins by 0) separated by comma')
|
|
32
34
|
.action(async (options: any) => { await this.commandList(options) })
|
|
33
35
|
}
|
|
@@ -38,7 +40,11 @@ class AssetList extends Cmd {
|
|
|
38
40
|
|
|
39
41
|
const dbClient = new DBClient(this.dbManager)
|
|
40
42
|
dbClient.selectFromTable('List of Assets', 'cyk_asset',
|
|
41
|
-
{
|
|
43
|
+
{
|
|
44
|
+
fields: 'asset_id,asset_route,asset_auth,asset_access,asset_mimetype,asset_last_update', sort: options.sort || '1',
|
|
45
|
+
where: (options.dest ? "asset_route like '" + options.dest + "%'" : undefined)
|
|
46
|
+
}
|
|
47
|
+
|
|
42
48
|
)
|
|
43
49
|
}
|
|
44
50
|
catch (err) {
|
|
@@ -47,27 +53,28 @@ class AssetList extends Cmd {
|
|
|
47
53
|
}
|
|
48
54
|
}
|
|
49
55
|
|
|
50
|
-
//----------------------------------------------------------------------------------------------
|
|
51
|
-
// class AssetUpload
|
|
52
|
-
//----------------------------------------------------------------------------------------------
|
|
53
|
-
|
|
54
56
|
interface FileDescriptor {
|
|
55
57
|
path: string
|
|
56
58
|
mtime: Date
|
|
57
59
|
id?: number
|
|
58
60
|
}
|
|
59
|
-
|
|
61
|
+
/**
|
|
62
|
+
* class AssetU
|
|
63
|
+
*/
|
|
64
|
+
class AssetU extends Cmd {
|
|
60
65
|
|
|
61
66
|
constructor(name: string, description: string) {
|
|
62
67
|
super(name)
|
|
63
68
|
this.description(description)
|
|
64
|
-
.option('-
|
|
69
|
+
.option('-i --id <id>', 'asset id to update properties')
|
|
70
|
+
.option('--auth <auth_schema>', 'authentication schema : basic | token | cookie | any | none, default is none')
|
|
71
|
+
.option('--access <access>', 'access rights required')
|
|
65
72
|
.option('-d --dest <destination>', 'destination path, directory name')
|
|
66
73
|
.option('-c --clean', 'clean destination path before uploading')
|
|
67
74
|
.option('-y --yes', 'upload list is automatically confirmed')
|
|
68
75
|
.argument('[sources...]', 'local files or directories to upload as assets to the server')
|
|
69
76
|
.action(async (sources: any, options: any) => {
|
|
70
|
-
await this.
|
|
77
|
+
await this.commandU(sources, options)
|
|
71
78
|
})
|
|
72
79
|
}
|
|
73
80
|
|
|
@@ -82,6 +89,51 @@ class AssetUpload extends Cmd {
|
|
|
82
89
|
return result
|
|
83
90
|
}
|
|
84
91
|
|
|
92
|
+
/**
|
|
93
|
+
* method commandU
|
|
94
|
+
* @param sources
|
|
95
|
+
* @param options
|
|
96
|
+
*/
|
|
97
|
+
async commandU(sources: string[], options: any) {
|
|
98
|
+
if (sources.length > 0) {
|
|
99
|
+
// upload
|
|
100
|
+
logger.debug('upload sources :', sources)
|
|
101
|
+
await this.commandUpload(sources, options)
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
// update
|
|
105
|
+
logger.debug('update', options)
|
|
106
|
+
await this.commandUpdate(options)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* method commandUpdate
|
|
112
|
+
* @param options
|
|
113
|
+
*/
|
|
114
|
+
async commandUpdate(options: any) {
|
|
115
|
+
try {
|
|
116
|
+
await this.prologue(options)
|
|
117
|
+
if (this.dbManager === undefined) throw 'dbManager undefined'
|
|
118
|
+
|
|
119
|
+
if (options.id === undefined) throw '<id_or_route> of asset to update is missing'
|
|
120
|
+
|
|
121
|
+
const dbAsset = await this.dbManager.dbAssetExist(options.id)
|
|
122
|
+
if (dbAsset === undefined) throw 'Asset ' + options.id + ' not found'
|
|
123
|
+
|
|
124
|
+
await this.updateAuthAccess('cyk_asset', 'assert', dbAsset.id || '', options)
|
|
125
|
+
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
logger.error(err)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* method commandUpload
|
|
134
|
+
* @param sources
|
|
135
|
+
* @param options
|
|
136
|
+
*/
|
|
85
137
|
async commandUpload(sources: string[], options: any) {
|
|
86
138
|
|
|
87
139
|
try {
|
|
@@ -90,8 +142,8 @@ class AssetUpload extends Cmd {
|
|
|
90
142
|
|
|
91
143
|
if (sources.length === 0) throw 'no source to upload'
|
|
92
144
|
|
|
93
|
-
if (
|
|
94
|
-
throw 'valid authentication schemas are : basic | token | any'
|
|
145
|
+
if (options.auth && ' basic | token | cookie | any | none'.indexOf(options.auth) === -1) {
|
|
146
|
+
throw 'valid authentication schemas are : basic | token | cookie | any | none'
|
|
95
147
|
}
|
|
96
148
|
logger.debug('options : ', options)
|
|
97
149
|
logger.debug('auth : ' + options.auth)
|
|
@@ -131,7 +183,7 @@ class AssetUpload extends Cmd {
|
|
|
131
183
|
async cleanDestination(dest: string) {
|
|
132
184
|
|
|
133
185
|
const remoteList = await this.scanAssets()
|
|
134
|
-
for(let ind = 0; ind < remoteList.length; ind++) {
|
|
186
|
+
for (let ind = 0; ind < remoteList.length; ind++) {
|
|
135
187
|
const fd = remoteList[ind]
|
|
136
188
|
if (fd.path.startsWith(dest)) {
|
|
137
189
|
const url = '/api/admin/assets/' + fd.id
|
|
@@ -314,7 +366,8 @@ class AssetUpload extends Cmd {
|
|
|
314
366
|
dbAsset.mimetype = mimetype
|
|
315
367
|
dbAsset.route = route
|
|
316
368
|
dbAsset.auth = auth
|
|
317
|
-
|
|
369
|
+
if (dbAsset.auth === 'none') dbAsset.auth = undefined
|
|
370
|
+
|
|
318
371
|
// const fstat = fs.statSync(fileName)
|
|
319
372
|
dbAsset.last_update = upload.mtime
|
|
320
373
|
|
package/src/Cmd.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { Command } from "commander";
|
|
|
3
3
|
import dotenv from 'dotenv'
|
|
4
4
|
import loglevel from 'loglevel'
|
|
5
5
|
import { NodeCrypto } from "./NodeCrypto";
|
|
6
|
+
import { DBClient } from "./DBClient";
|
|
6
7
|
const logger = loglevel.getLogger('Cmd.ts')
|
|
7
8
|
logger.setLevel('debug')
|
|
8
9
|
|
|
@@ -35,4 +36,62 @@ export class Cmd extends Command {
|
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* method updateAuthAccess
|
|
42
|
+
* @param tableName
|
|
43
|
+
* @param prefix
|
|
44
|
+
* @param id
|
|
45
|
+
* @param options
|
|
46
|
+
*/
|
|
47
|
+
async updateAuthAccess(tableName: string, prefix: string, id: string, options: any) {
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
|
|
51
|
+
let dclAuth: string | undefined
|
|
52
|
+
|
|
53
|
+
if (options.auth) {
|
|
54
|
+
if (' basic | token | cookie | any | none | null '.indexOf(' ' + options.auth + ' ') === -1) {
|
|
55
|
+
throw 'valid authentication schemas are : basic | token | cookie | any | null'
|
|
56
|
+
}
|
|
57
|
+
dclAuth = `<string name='${prefix}_auth'>`
|
|
58
|
+
if (' none | null '.indexOf(' ' + options.auth + ' ') === -1)
|
|
59
|
+
dclAuth += ` "${options.auth}" `
|
|
60
|
+
else
|
|
61
|
+
dclAuth += ' null '
|
|
62
|
+
dclAuth += "</string>"
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let dclAccess: string | undefined
|
|
66
|
+
|
|
67
|
+
if (options.access) {
|
|
68
|
+
|
|
69
|
+
dclAccess = `<string name='${prefix}_access'> `
|
|
70
|
+
if (' null | none '.indexOf(' ' + options.access + ' ') === -1)
|
|
71
|
+
dclAccess += `"${options.access}"`
|
|
72
|
+
else
|
|
73
|
+
dclAccess += ' null '
|
|
74
|
+
dclAccess += "</string>"
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const inst = `
|
|
78
|
+
<db.update table='${tableName}'>
|
|
79
|
+
<object>
|
|
80
|
+
<number name='${prefix}_id'>${id}</number>
|
|
81
|
+
${dclAuth}
|
|
82
|
+
${dclAccess ? dclAccess : ''}
|
|
83
|
+
</object>
|
|
84
|
+
</db.update>
|
|
85
|
+
`
|
|
86
|
+
|
|
87
|
+
if (! this.dbManager) throw 'prologue() has not been called before'
|
|
88
|
+
|
|
89
|
+
const dbClient = new DBClient(this.dbManager)
|
|
90
|
+
dbClient.execInstructions(inst)
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
logger.error(err)
|
|
94
|
+
throw err
|
|
95
|
+
}
|
|
96
|
+
}
|
|
38
97
|
}
|
package/src/DBClient.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { BasicType, DBColumn, DBExecuteRequest, DBManager, DBTable, ObjectData, parseXML, PrimitiveData } from "@cyklang/core";
|
|
1
|
+
import { BasicType, DBColumn, DBExecuteRequest, DBManager, DBTable, ObjectData, parseXML, PrimitiveData, Script, XmlError } from "@cyklang/core";
|
|
2
2
|
import loglevel from "loglevel";
|
|
3
|
+
import { errorconsole } from "./console";
|
|
3
4
|
const logger = loglevel.getLogger('DBClient.ts')
|
|
4
5
|
logger.setLevel('debug')
|
|
5
6
|
// DBManager wrapper class
|
|
@@ -10,6 +11,39 @@ export class DBClient {
|
|
|
10
11
|
this.dbManager = dbManager
|
|
11
12
|
}
|
|
12
13
|
|
|
14
|
+
/**
|
|
15
|
+
* method execInstructions
|
|
16
|
+
* @param source
|
|
17
|
+
*/
|
|
18
|
+
async execInstructions(source: string) {
|
|
19
|
+
const script = `<?xml-model href="https://www.cyklang.net/schema/cyklang.xsd" type="application/xml" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
|
20
|
+
<module>
|
|
21
|
+
` + source + `
|
|
22
|
+
</module>`
|
|
23
|
+
await this.execScript(script)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* method execScript
|
|
28
|
+
* @param source
|
|
29
|
+
*/
|
|
30
|
+
async execScript(source: string) {
|
|
31
|
+
try {
|
|
32
|
+
const script = new Script(this.dbManager.scope, '', source)
|
|
33
|
+
await script.parseInstructions()
|
|
34
|
+
await script.execute()
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
console.log(source)
|
|
38
|
+
console.log()
|
|
39
|
+
if (err instanceof XmlError) {
|
|
40
|
+
let xmlError = <XmlError>err
|
|
41
|
+
errorconsole(xmlError)
|
|
42
|
+
}
|
|
43
|
+
console.log(err)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
13
47
|
async runQuery() {
|
|
14
48
|
|
|
15
49
|
}
|
package/src/ModuleCommand.ts
CHANGED
|
@@ -14,11 +14,11 @@ export class ModuleCommand extends Command {
|
|
|
14
14
|
super(name)
|
|
15
15
|
this.description('manage modules')
|
|
16
16
|
// upload
|
|
17
|
-
this.addCommand(new
|
|
17
|
+
this.addCommand(new ModuleU('upload', `Upload local module file(s) to the database.
|
|
18
18
|
Module name is the base name of the file. If a module with the same name already exists, it will be updated.
|
|
19
19
|
Otherwise, a new module is inserted in the database. To rename a module, use option --id to indicate the module you want to rename`)
|
|
20
20
|
)
|
|
21
|
-
this.addCommand(new
|
|
21
|
+
this.addCommand(new ModuleU('u', 'shortcut for (u)pload'))
|
|
22
22
|
// download
|
|
23
23
|
this.addCommand(new ModuleDownload('download', 'download module files to the current directory'))
|
|
24
24
|
this.addCommand(new ModuleDownload('d', 'shortcut for (d)ownload'))
|
|
@@ -45,16 +45,57 @@ interface UploadOptions {
|
|
|
45
45
|
id: string | undefined
|
|
46
46
|
env: string | undefined
|
|
47
47
|
}
|
|
48
|
-
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* class ModuleU
|
|
51
|
+
*/
|
|
52
|
+
class ModuleU extends Cmd {
|
|
49
53
|
constructor(name: string, description: string) {
|
|
50
54
|
super(name)
|
|
51
55
|
this.description(description)
|
|
52
|
-
.option('
|
|
56
|
+
.option('--auth <auth_schema>', 'authentication schema : basic | token | cookie | any | none, default is none')
|
|
57
|
+
.option('--access <access_right>', 'access rights required')
|
|
58
|
+
.option('-i --id <id>', 'module ID to upload or update')
|
|
53
59
|
.argument('[files...]', 'local module file(s) to upload to the server')
|
|
54
60
|
.action(async (files: any, options: any) => {
|
|
55
|
-
await this.
|
|
61
|
+
await this.commandU(files, options)
|
|
56
62
|
})
|
|
57
63
|
}
|
|
64
|
+
|
|
65
|
+
async commandU(files: string[], options: any) {
|
|
66
|
+
if (files.length > 0) {
|
|
67
|
+
await this.commandUpload(files, options)
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
await this.commandUpdate(options)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* method commandUpdate
|
|
76
|
+
* @param options
|
|
77
|
+
*/
|
|
78
|
+
async commandUpdate(options: any) {
|
|
79
|
+
try {
|
|
80
|
+
await this.prologue(options)
|
|
81
|
+
if (this.dbManager === undefined) throw 'dbManager undefined'
|
|
82
|
+
|
|
83
|
+
if (options.id === undefined) throw '<id_or_route> of module to update is missing'
|
|
84
|
+
|
|
85
|
+
const dbModule = await this.dbManager.getModule(options.id)
|
|
86
|
+
|
|
87
|
+
await this.updateAuthAccess('cyk_module', 'module', dbModule.id || '', options)
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
logger.error(err)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* method commandUpload
|
|
96
|
+
* @param files
|
|
97
|
+
* @param options
|
|
98
|
+
*/
|
|
58
99
|
async commandUpload(files: string[], options: UploadOptions) {
|
|
59
100
|
try {
|
|
60
101
|
await this.prologue(options)
|
package/src/TableCommand.ts
CHANGED
|
@@ -22,6 +22,47 @@ export class TableCommand extends Command {
|
|
|
22
22
|
this.addCommand(new TableList('l', '(l)ist database tables'))
|
|
23
23
|
this.addCommand(new TableData('data', 'table (d)ata'))
|
|
24
24
|
this.addCommand(new TableData('d', 'table (d)ata'))
|
|
25
|
+
this.addCommand(new TableUpdate('update', 'update table properties'))
|
|
26
|
+
this.addCommand(new TableUpdate('u', 'shortcut for (u)pdate table properties'))
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* class TableUpdate
|
|
32
|
+
*/
|
|
33
|
+
class TableUpdate extends Cmd {
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
*
|
|
37
|
+
* @param name
|
|
38
|
+
* @param description
|
|
39
|
+
*/
|
|
40
|
+
constructor(name: string, description: string) {
|
|
41
|
+
super(name)
|
|
42
|
+
this.description(description)
|
|
43
|
+
.option('-n --name <table_name>', 'name of the table whose properties are to be changed')
|
|
44
|
+
.option('--auth <auth_schema>', 'authentication schema : basic | token | cookie | any | none, default is none')
|
|
45
|
+
.option('--access <access>', 'access rights required')
|
|
46
|
+
.action(async (options: any) => {
|
|
47
|
+
await this.commandUpdate(options)
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async commandUpdate(options: any) {
|
|
52
|
+
try {
|
|
53
|
+
await this.prologue(options)
|
|
54
|
+
if (this.dbManager === undefined) throw 'dbManager undefined'
|
|
55
|
+
|
|
56
|
+
if ( ! options.name ) throw '<table_name> is missing'
|
|
57
|
+
|
|
58
|
+
const dbTable = await this.dbManager.dbTableExist(options.name)
|
|
59
|
+
if ( ! dbTable ) throw 'Table ' + options.name + ' not found'
|
|
60
|
+
|
|
61
|
+
await this.updateAuthAccess('cyk_table', 'table', dbTable.id || '', options)
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
logger.error(err)
|
|
65
|
+
}
|
|
25
66
|
}
|
|
26
67
|
}
|
|
27
68
|
|
package/src/UserCommand.ts
CHANGED
|
@@ -17,6 +17,7 @@ export class UserCommand extends Command {
|
|
|
17
17
|
this.addCommand(new UserUpdateCmd('u', 'shortcut for (u)pdate'))
|
|
18
18
|
this.addCommand(new UserDeleteCmd('delete', 'delete user by id and name. Both options are mandatory to avoid typing error'))
|
|
19
19
|
this.addCommand(new UserPasswdCmd('passwd', 'change user password'))
|
|
20
|
+
this.addCommand(new UserPasswdCmd('p', 'shortcut for (p)asswd'))
|
|
20
21
|
this.addCommand(new UserListCmd('list', 'list users'))
|
|
21
22
|
this.addCommand(new UserListCmd('l', 'shortcut for (l)ist'))
|
|
22
23
|
}
|
|
@@ -41,7 +42,7 @@ class UserAddCmd extends Cmd {
|
|
|
41
42
|
this.description(description)
|
|
42
43
|
.requiredOption('-n --name <name>', 'user name')
|
|
43
44
|
.option('-e --email <email>', 'user email address')
|
|
44
|
-
.option('-p --
|
|
45
|
+
.option('-p --password <password>', 'initial password')
|
|
45
46
|
.option('-a --access <acl>', 'access control list')
|
|
46
47
|
.option('-m --module <module_name>', 'module to launch by default')
|
|
47
48
|
.option('-d --disable', 'user not abled to connect')
|
|
@@ -63,7 +64,11 @@ class UserAddCmd extends Cmd {
|
|
|
63
64
|
await this.prologue(options)
|
|
64
65
|
if (this.dbManager === undefined) throw 'dbManager undefined'
|
|
65
66
|
const result = await this.dbManager.dbUserInsert(dbUser)
|
|
66
|
-
logger.debug(result)
|
|
67
|
+
logger.debug('ID', result)
|
|
68
|
+
if (dbUser.password) {
|
|
69
|
+
await this.dbManager.dbUserPasswd(result, dbUser.password)
|
|
70
|
+
logger.info('password changed for user ' + dbUser.name)
|
|
71
|
+
}
|
|
67
72
|
}
|
|
68
73
|
catch (err) {
|
|
69
74
|
logger.error(err)
|
|
@@ -174,7 +179,7 @@ class UserDeleteCmd extends Cmd {
|
|
|
174
179
|
|
|
175
180
|
class UserPasswdCmd extends Cmd {
|
|
176
181
|
constructor(name: string, description: string) {
|
|
177
|
-
super(
|
|
182
|
+
super(name)
|
|
178
183
|
|
|
179
184
|
this.description(description)
|
|
180
185
|
.requiredOption('-i --id <id>', 'user ID')
|
package/test/t26.output
CHANGED
|
@@ -3,3 +3,10 @@ date : <b>Gras</b> <i>Italic </i>
|
|
|
3
3
|
format 1 : Format sans paramètre
|
|
4
4
|
format 2 : Nom : CYK Final
|
|
5
5
|
format 3 : Nom : { CYK Prénom Philippe }
|
|
6
|
+
{"name":"CYK","surname":"Philippe","adresses":[{"town":"Saint-Denis","department":"Reunion"},{"town":"Paris","department":"Paris"}]}
|
|
7
|
+
var1 = undefined
|
|
8
|
+
var2 = undefined
|
|
9
|
+
var1 == var2
|
|
10
|
+
after set var2 from var1
|
|
11
|
+
var1 == var2
|
|
12
|
+
var1 == var3
|
package/test/t26.xml
CHANGED
|
@@ -31,5 +31,42 @@
|
|
|
31
31
|
</object>
|
|
32
32
|
|
|
33
33
|
<print>json(person)</print>
|
|
34
|
+
|
|
35
|
+
<string name="var1"/>
|
|
36
|
+
<string name="var2"/>
|
|
37
|
+
<print>"var1 = " + var1</print>
|
|
38
|
+
<print>"var2 = " + var2</print>
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
<if>
|
|
42
|
+
<condition>var1 == var2</condition>
|
|
43
|
+
<then>
|
|
44
|
+
<print>"var1 == var2"</print>
|
|
45
|
+
</then>
|
|
46
|
+
</if>
|
|
47
|
+
|
|
48
|
+
<set name="var2">var1</set>
|
|
49
|
+
<print>"after set var2 from var1"</print>
|
|
50
|
+
|
|
51
|
+
<if>
|
|
52
|
+
<condition>var1 == var2</condition>
|
|
53
|
+
<then>
|
|
54
|
+
<print>"var1 == var2"</print>
|
|
55
|
+
</then>
|
|
56
|
+
</if>
|
|
57
|
+
|
|
58
|
+
<string name="var3">var1</string>
|
|
59
|
+
|
|
60
|
+
<if>
|
|
61
|
+
<condition>var1 == var3</condition>
|
|
62
|
+
<then>
|
|
63
|
+
<print>"var1 == var3"</print>
|
|
64
|
+
</then>
|
|
65
|
+
<else>
|
|
66
|
+
<print>"var1 !== var3"</print>
|
|
67
|
+
</else>
|
|
68
|
+
</if>
|
|
69
|
+
|
|
70
|
+
|
|
34
71
|
|
|
35
72
|
</module>
|