Skip to content

Commit bbb26b3

Browse files
committed
Added command - import template
1 parent e547b1c commit bbb26b3

File tree

11 files changed

+168
-123
lines changed

11 files changed

+168
-123
lines changed

package.json

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,11 @@
381381
"title": "Open template folder",
382382
"category": "FastIoT"
383383
},
384+
{
385+
"command": "viewTemplates.ImportTemplate",
386+
"title": "Import template",
387+
"category": "FastIoT"
388+
},
384389
{
385390
"command": "viewTemplates.RestoreSystemTemplates",
386391
"title": "Restore/upgrade system templates (offline)",
@@ -476,15 +481,23 @@
476481
},
477482
{
478483
"command": "viewTemplates.ReloadTemplates",
479-
"when": "view == viewTemplates"
484+
"when": "view == viewTemplates",
485+
"group": "2_workspace"
480486
},
481487
{
482-
"command": "viewTemplates.OpenTemplateFolder",
483-
"when": "view == viewTemplates"
488+
"command": "viewTemplates.RestoreSystemTemplates",
489+
"when": "view == viewTemplates",
490+
"group": "2_workspace"
484491
},
485492
{
486-
"command": "viewTemplates.RestoreSystemTemplates",
487-
"when": "view == viewTemplates"
493+
"command": "viewTemplates.ImportTemplate",
494+
"when": "view == viewTemplates",
495+
"group": "7_modification"
496+
},
497+
{
498+
"command": "viewTemplates.OpenTemplateFolder",
499+
"when": "view == viewTemplates",
500+
"group": "7_modification"
488501
}
489502
],
490503
"view/item/context": [

src/Entity/EntityBase.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ import { FilesValidator } from '../Validator/FilesValidator';
1111
export abstract class EntityBase<T extends EntityBaseAttribute> {
1212
protected readonly _entityLabel:string; //for understandable log
1313
protected readonly _entitiesLabel:string; //for understandable log
14-
private _yamlFilePath:string=""; //YAML file
14+
private _yamlFilePath:string="";
15+
/**
16+
* YAML main file *.fastiot.yaml. Ex: ..\dotnet-console\template.fastiot.yaml
17+
*
18+
*/
1519
public get YAMLFilePath(): string {
1620
return this._yamlFilePath;}
1721
public get RootDir(): string {
@@ -100,6 +104,8 @@ export abstract class EntityBase<T extends EntityBaseAttribute> {
100104
public Move(destDir:string):IotResult {
101105
let result:IotResult;
102106
try {
107+
//dir
108+
destDir=path.join(destDir, this.Attributes.Id);
103109
//delete
104110
if (fs.existsSync(destDir)) {
105111
fs.emptyDirSync(destDir);
@@ -111,6 +117,7 @@ export abstract class EntityBase<T extends EntityBaseAttribute> {
111117
const fileName=this.YAMLFilePath.substring(this.RootDir.length+1);
112118
this._yamlFilePath= path.join(destDir, fileName);
113119
result = new IotResult(StatusResult.Ok,`${this._entityLabel}. ${this.RootDir} folder successfully moved to ${destDir} folder`);
120+
result.returnObject=destDir;
114121
} catch (err: any){
115122
result = new IotResult(StatusResult.Error,`Unable to move ${this._entityLabel} from folder ${this.RootDir} to folder ${destDir}`,err);
116123
}

src/Entity/EntityCollection.ts

Lines changed: 90 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ export abstract class EntityCollection <A extends EntityBaseAttribute, T extends
103103
if(result==0) {
104104
return ContainsType.yesSameVersion;
105105
} else if (result==1) return ContainsType.yesVersionSmaller;
106-
return ContainsType.yesMoreVersion;
106+
return ContainsType.yesNewerVersion;
107107
}
108108

109109
public SelectByEndDeviceArchitecture(endDeviceArchitecture?:string):Array<T>
@@ -123,7 +123,7 @@ export abstract class EntityCollection <A extends EntityBaseAttribute, T extends
123123
return this._items.get(idEntity);
124124
}
125125

126-
protected async LoadFromFolder(pathFolder:string, type:EntityType):Promise<IotResult>
126+
protected async LoadEntitiesFromFolder(pathFolder:string, type:EntityType):Promise<IotResult>
127127
{
128128
let result:IotResult;
129129
try {
@@ -144,7 +144,7 @@ export abstract class EntityCollection <A extends EntityBaseAttribute, T extends
144144
let dir:string;
145145
for (let i = 0; i < listFolders.length; i++) {
146146
dir=listFolders[i];
147-
await this.ImportEntity(dir,type);
147+
await this.LoadOneEntityFromFolder(dir,type);
148148
}
149149
//result
150150
if((this.Count-entitysCountBegin)>0) {
@@ -160,14 +160,45 @@ export abstract class EntityCollection <A extends EntityBaseAttribute, T extends
160160
return Promise.resolve(result);
161161
}
162162

163-
protected async ImportEntity(dir:string,type:EntityType):Promise<IotResult>
163+
protected async ImportEntityFromZip(fileZipPath:string,type:EntityType):Promise<IotResult>
164+
{
165+
let result:IotResult;
166+
//unpack to current dir
167+
let unpackDir=path.join(path.dirname(fileZipPath), path.parse(fileZipPath).name);
168+
try {
169+
result=IoTHelper.UnpackFromZip(fileZipPath,unpackDir);
170+
if(result.Status!=StatusResult.Ok) return Promise.resolve(result);
171+
//test
172+
result=await this.LoadOneEntityFromFolder(unpackDir,type,true);
173+
if(result.Status!=StatusResult.Ok) return Promise.resolve(result);
174+
//move
175+
let entity:T;
176+
entity=<T>result.returnObject;
177+
result=entity.Move(this.GetDirEntitiesCallback(type));
178+
if(result.Status!=StatusResult.Ok) return Promise.resolve(result);
179+
//add
180+
unpackDir=<string>result.returnObject;
181+
result=await this.LoadOneEntityFromFolder(unpackDir,type);
182+
} catch (err: any){
183+
result = new IotResult(StatusResult.Error,`${this._entityLabel} import error. File: ${fileZipPath}, type ${type}.`,err);
184+
//clear
185+
if (fs.existsSync(unpackDir)) {
186+
fs.emptyDirSync(unpackDir);
187+
fs.removeSync(unpackDir);
188+
}
189+
}
190+
//result
191+
return Promise.resolve(result);
192+
}
193+
194+
protected async LoadOneEntityFromFolder(dir:string,type:EntityType,isTest:boolean=false):Promise<IotResult>
164195
{
165196
let result:IotResult;
166197
try {
167198
const filePath=`${dir}\\${this._entityLabel.toLowerCase()}.fastiot.yaml`;
168199
let entity = new this.TCreator(this.Config.schemasFolderPath);
169200
entity.Init(type,filePath,this.Config.recoverySourcePath);
170-
if(!entity.IsValid&&type==EntityType.system) {
201+
if(!isTest&&!entity.IsValid&&type==EntityType.system) {
171202
//Recovery
172203
this.CreateEvent(`${this._entityLabel} recovery: ${path.dirname(filePath)}`,LogLevel.Debug);
173204
result= entity.Recovery();
@@ -179,20 +210,26 @@ export abstract class EntityCollection <A extends EntityBaseAttribute, T extends
179210
}
180211
//main
181212
if(entity.IsValid) {
182-
this.CreateEvent(`${this._entityLabel} is valid: [${entity.Attributes.Id}]`,LogLevel.Debug);
213+
if(!isTest) this.CreateEvent(`${this._entityLabel} is valid: [${entity.Attributes.Id}]`,LogLevel.Debug);
183214
if(this.IsCompatibleByVersionExtAndPlatform(entity)) {
184215
const isContains=this.Contains(entity);
185216
switch(isContains) {
186217
case ContainsType.no: {
187-
this.Add(entity);
188-
this.CreateEvent(`${this._entityLabel} added: [${entity.Attributes.Id}] ${entity.RootDir}`,LogLevel.Debug);
218+
if(!isTest) {
219+
this.Add(entity);
220+
this.CreateEvent(`${this._entityLabel} added: [${entity.Attributes.Id}] ${entity.RootDir}`,LogLevel.Debug);
221+
}
189222
result = new IotResult(StatusResult.Ok,`${this._entityLabel} added: [${entity.Attributes.Id}] ${entity.RootDir}`);
223+
result.returnObject=entity;
190224
break;
191225
}
192226
case ContainsType.yesVersionSmaller: {
193-
this.Update(entity);
194-
this.CreateEvent(`${this._entityLabel} updated: [${entity.Attributes.Id}] ${entity.RootDir}`,LogLevel.Debug);
227+
if(!isTest) {
228+
this.Update(entity);
229+
this.CreateEvent(`${this._entityLabel} updated: [${entity.Attributes.Id}] ${entity.RootDir}`,LogLevel.Debug);
230+
}
195231
result = new IotResult(StatusResult.Ok,`${this._entityLabel} updated: [${entity.Attributes.Id}] ${entity.RootDir}`);
232+
result.returnObject=entity;
196233
break;
197234
}
198235
default: {
@@ -211,19 +248,20 @@ export abstract class EntityCollection <A extends EntityBaseAttribute, T extends
211248
this.CreateEvent(result);
212249
this.CreateEvent(entity.ValidationErrorsToString,LogLevel.Debug);
213250
//delete system entity
214-
if(type==EntityType.system) {
251+
if(!isTest&&type==EntityType.system) {
215252
result= entity.Remove();
216253
this.CreateEvent(result,LogLevel.Debug);
217254
}
218255
}
219256
} catch (err: any){
220-
result= new IotResult(StatusResult.Error,`Error import ${type} ${this._entitiesLabel} dir ${dir}`,err);
257+
result= new IotResult(StatusResult.Error,`Error load ${type} ${this._entitiesLabel} dir ${dir}`,err);
221258
}
222259
return Promise.resolve(result);
223260
}
224261

225262
protected async UpdateEntitiesFromUrl(url:string,type:EntityType):Promise<IotResult>
226263
{
264+
//download list
227265
const destPath= this.GetDirEntitiesCallback(type);
228266
let downloader = new EntityDownloader();
229267
let result:IotResult;
@@ -239,72 +277,47 @@ export abstract class EntityCollection <A extends EntityBaseAttribute, T extends
239277
result= new IotResult(StatusResult.Ok,`Url: ${url}. No ${this._entitiesLabel} to download`);
240278
return Promise.resolve(result);
241279
}
242-
//next
280+
//filter
243281
let index:number=0;
244282
do{
245283
let item = listDownload[index];
246284
if(item) {
247-
//parse
248-
if(this.IsCompatibleByVersionExtAndPlatform2(item.ForVersionExt,item.platform)) {
249-
const isContains=this.Contains2(item.Id,EntityType.system,item.Version);
250-
switch(isContains) {
251-
case ContainsType.no: {
252-
result= await downloader.DownloadEntity(item,this.Config.tempFolderPath);
253-
if(result.Status==StatusResult.Ok) {
254-
const unpackPath= <string> result.returnObject;
255-
const filePath = path.join(unpackPath, `${this._entityLabel.toLowerCase()}.fastiot.yaml`);
256-
let entity= new this.TCreator(this.Config.schemasFolderPath);
257-
entity.Init(EntityType.system,filePath);
258-
if(entity.IsValid) {
259-
result=entity.Move(path.join(destPath, entity.Attributes.Id));
260-
if(result.Status==StatusResult.Error) {
261-
this.CreateEvent(result,LogLevel.Debug);
262-
break;
263-
}
264-
this.Add(entity);
265-
this.CreateEvent(`${this._entityLabel} added/updated: [${entity.Attributes.Id}] ${entity.RootDir}`,LogLevel.Debug);
266-
} else {
267-
result = new IotResult(StatusResult.Error,`The ${this._entityLabel} ${entity.YAMLFilePath} has not been validated`)
268-
this.CreateEvent(result,LogLevel.Debug);
269-
this.CreateEvent(entity.ValidationErrorsToString,LogLevel.Debug);
270-
}
271-
}
272-
break;
273-
}
274-
case ContainsType.yesVersionSmaller: {
275-
result= await downloader.DownloadEntity(item,this.Config.tempFolderPath);
276-
if(result.Status==StatusResult.Ok) {
277-
const unpackPath= <string> result.returnObject;
278-
const filePath = path.join(unpackPath, ` ${this._entityLabel.toLowerCase()}.fastiot.yaml`);
279-
let entity= new this.TCreator(this.Config.schemasFolderPath);
280-
entity.Init(EntityType.system,filePath);
281-
if(entity.IsValid) {
282-
result=entity.Move(path.join(destPath, entity.Attributes.Id));
283-
if(result.Status==StatusResult.Error) {
284-
this.CreateEvent(result,LogLevel.Debug);
285-
break;
286-
}
287-
this.Update(entity);
288-
this.CreateEvent(`${this._entityLabel} added/updated: [${entity.Attributes.Id}] ${entity.RootDir}`,LogLevel.Debug);
289-
} else {
290-
result = new IotResult(StatusResult.Error,`The ${this._entityLabel} ${entity.YAMLFilePath} has not been validated`)
291-
this.CreateEvent(result,LogLevel.Debug);
292-
this.CreateEvent(entity.ValidationErrorsToString,LogLevel.Debug);
293-
}
294-
}
295-
}
296-
default: {
297-
//statements;
298-
break;
299-
}
300-
}
301-
}else{
302-
result = new IotResult(StatusResult.Error,`Error. The ${this._entityLabel} ${item.Url} is for a newer version of the extension. ` +
303-
`Update the extension.`);
285+
//check
286+
if(this.IsCompatibleByVersionExtAndPlatform2(item.ForVersionExt,item.platform)) {
287+
const isContains=this.Contains2(item.Id,EntityType.system,item.Version);
288+
if(isContains==ContainsType.yesSameVersion || isContains==ContainsType.yesNewerVersion) {
289+
//remove
290+
listDownload.splice(index, 1);
291+
index--;
292+
}
293+
} else {
294+
//remove
295+
listDownload.splice(index, 1);
296+
index--;
297+
}
298+
}else break;
299+
index++;
300+
}while(true)
301+
//add entities
302+
index=0;
303+
do{
304+
let item = listDownload[index];
305+
if (!item) break; // exit do
306+
//download entity
307+
result= await downloader.DownloadEntity(item,this.Config.tempFolderPath);
308+
this.CreateEvent(result,LogLevel.Debug);
309+
//add entity
310+
if(result.Status==StatusResult.Ok) {
311+
const fileZipPath = <string> result.returnObject;
312+
result= await this.ImportEntityFromZip(fileZipPath,type);
313+
if(result.Status==StatusResult.Ok) {
314+
//delete zip
315+
fs.removeSync(fileZipPath);
316+
}else {
304317
this.CreateEvent(result,LogLevel.Debug);
305318
}
306-
//
307-
}else break;
319+
}
320+
//next index
308321
index++;
309322
}while(true)
310323
//result
@@ -337,11 +350,11 @@ export abstract class EntityCollection <A extends EntityBaseAttribute, T extends
337350
return Promise.resolve(result);
338351
}
339352

340-
protected async LoadEntities(type:EntityType):Promise<void>
353+
protected async LoadEntitiesByType(type:EntityType):Promise<void>
341354
{
342355
this.CreateEvent(`☑️ Loading ${type} ${this._entitiesLabel}`,LogLevel.Debug);
343356
const path=this.GetDirEntitiesCallback(type);
344-
const result = await this.LoadFromFolder(path,type);
357+
const result = await this.LoadEntitiesFromFolder(path,type);
345358
this.CreateEvent(result,LogLevel.Debug);
346359
}
347360

@@ -357,7 +370,7 @@ export abstract class EntityCollection <A extends EntityBaseAttribute, T extends
357370
LogLevel.Information);
358371
//Loading system entities
359372
this.CreateEvent(`Loading system ${this._entitiesLabel}`,undefined,15); //15
360-
await this.LoadEntities(EntityType.system);
373+
await this.LoadEntitiesByType(EntityType.system);
361374
//Updating system entities
362375
this.CreateEvent(`Updating system ${this._entitiesLabel}`,undefined,15); //30
363376
//To get the number of hours since Unix epoch, i.e. Unix timestamp:
@@ -379,7 +392,7 @@ export abstract class EntityCollection <A extends EntityBaseAttribute, T extends
379392
}
380393
//Loading community entities
381394
this.CreateEvent(`Loading community ${this._entitiesLabel}`,undefined,15); //45
382-
await this.LoadEntities(EntityType.community);
395+
await this.LoadEntitiesByType(EntityType.community);
383396
//Updating community entities
384397
this.CreateEvent(`Updating community ${this._entitiesLabel}`,undefined,15); //60
385398
if(force||isNeedUpdate()){
@@ -395,7 +408,7 @@ export abstract class EntityCollection <A extends EntityBaseAttribute, T extends
395408
}
396409
//Loading custom entities
397410
this.CreateEvent(`Loading custom ${this._entitiesLabel} templates loaded `,undefined,15); //75
398-
await this.LoadEntities(EntityType.user);
411+
await this.LoadEntitiesByType(EntityType.user);
399412
//result
400413
this.CreateEvent(new IotResult(StatusResult.Ok, `${this._entitiesLabel} loaded`));
401414
const endMsg=`📚 ${this.Count} ${this._entityLabel}(s) available.`;

src/Entity/EntityDownloader.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,7 @@ export class EntityDownloader {
1818
const fileZipPath = path.join(destPath, `${item.Id}.zip`);
1919
result=await networkHelper.DownloadFileHttp(item.Url,fileZipPath);
2020
if(result.Status!=StatusResult.Ok) return Promise.resolve(result);
21-
//unpack
22-
const unpackDir = path.join(destPath, item.Id);
23-
result=IoTHelper.UnpackFromZip(fileZipPath,unpackDir);
24-
if(result.Status!=StatusResult.Ok) return Promise.resolve(result);
25-
//delete zip
26-
fs.removeSync(fileZipPath);
27-
result = new IotResult(StatusResult.Ok);
28-
result.returnObject=unpackDir;
21+
result.returnObject=fileZipPath;
2922
} catch (err: any){
3023
result = new IotResult(StatusResult.Error,`Unable to download file ${item.Url}.`,err);
3124
}

src/Helper/IoTHelper.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ export class IoTHelper {
130130
static UnpackFromZip(fileZipPath:string, unpackDir:string):IotResult {
131131
let result:IotResult;
132132
try {
133+
//no file
134+
if (!fs.existsSync(fileZipPath)) {
135+
result = new IotResult(StatusResult.Error,`Unpack file not found ${fileZipPath}`);
136+
return result;
137+
}
133138
//clear
134139
if (fs.existsSync(unpackDir)) {
135140
fs.emptyDirSync(unpackDir);
@@ -143,7 +148,7 @@ export class IoTHelper {
143148
var zip = new AdmZip(fileZipPath);
144149
// extracts everything
145150
zip.extractAllTo(/*target path*/ unpackDir, /*overwrite*/ true);
146-
result = new IotResult(StatusResult.Ok);
151+
result = new IotResult(StatusResult.Ok, `The archive was successfully unpacked, path ${unpackDir}`);
147152
} catch (err: any){
148153
result = new IotResult(StatusResult.Error,`Error while unpacking file ${fileZipPath} to dir ${unpackDir}`,err);
149154
}

src/Helper/networkHelper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ export class networkHelper {
114114
outputLocationPath=path.join(outputLocationPath, fileName);
115115
}
116116
const finishedDownload = promisify(stream.finished);
117-
result = new IotResult(StatusResult.Ok,"File downloaded");
117+
result = new IotResult(StatusResult.Ok,`File downloaded Url ${fileUrl}`);
118118
if(outputLocationPath) {
119119
const response = await axios({
120120
method: 'GET',

0 commit comments

Comments
 (0)