Improved tasks.py - not is able to discover the "best" delphi version to use to compile (latest one)

This commit is contained in:
Daniele Teti 2023-11-06 14:46:39 +01:00
parent e1aa50dd86
commit 85d27bc00b
14 changed files with 234 additions and 124 deletions

11
.vscode/launch.json vendored
View File

@ -4,6 +4,7 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"name": "Python TASK generate-nullable", "name": "Python TASK generate-nullable",
"type": "python", "type": "python",
@ -14,6 +15,16 @@
], ],
"console": "integratedTerminal" "console": "integratedTerminal"
}, },
{
"name": "build-core",
"type": "python",
"request": "launch",
"module": "invoke",
"args": [
"build-core"
],
"console": "integratedTerminal"
},
{ {
"name": "Python TASK build-samples", "name": "Python TASK build-samples",
"type": "python", "type": "python",

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<ProjectGuid>{5B9408E7-46AC-4431-9716-C9EB9F8589B1}</ProjectGuid> <ProjectGuid>{5B9408E7-46AC-4431-9716-C9EB9F8589B1}</ProjectGuid>
<MainSource>SwagDoc.dpk</MainSource> <MainSource>SwagDoc.dpk</MainSource>
<ProjectVersion>20.1</ProjectVersion> <ProjectVersion>19.5</ProjectVersion>
<FrameworkType>None</FrameworkType> <FrameworkType>None</FrameworkType>
<Base>True</Base> <Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config> <Config Condition="'$(Config)'==''">Debug</Config>
@ -13,6 +13,16 @@
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''"> <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base> <Base>true</Base>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Android' and '$(Base)'=='true') or '$(Base_Android)'!=''">
<Base_Android>true</Base_Android>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Android64' and '$(Base)'=='true') or '$(Base_Android64)'!=''">
<Base_Android64>true</Base_Android64>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''"> <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
<Base_Win32>true</Base_Win32> <Base_Win32>true</Base_Win32>
<CfgParent>Base</CfgParent> <CfgParent>Base</CfgParent>
@ -54,6 +64,18 @@
<RuntimeOnlyPackage>true</RuntimeOnlyPackage> <RuntimeOnlyPackage>true</RuntimeOnlyPackage>
<DCC_OutputNeverBuildDcps>true</DCC_OutputNeverBuildDcps> <DCC_OutputNeverBuildDcps>true</DCC_OutputNeverBuildDcps>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Base_Android)'!=''">
<VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=</VerInfo_Keys>
<BT_BuildType>Debug</BT_BuildType>
<VerInfo_IncludeVerInfo>false</VerInfo_IncludeVerInfo>
<EnabledSysJars>activity-1.1.0.dex.jar;annotation-1.2.0.dex.jar;appcompat-1.2.0.dex.jar;appcompat-resources-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;biometric-1.1.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.1.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.1.0.dex.jar;core-runtime-2.1.0.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.2.5.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.2.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.2.0.dex.jar;lifecycle-runtime-2.2.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.2.0.dex.jar;lifecycle-viewmodel-savedstate-2.2.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;savedstate-1.0.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;vectordrawable-1.1.0.dex.jar;vectordrawable-animated-1.1.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar</EnabledSysJars>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Android64)'!=''">
<VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=</VerInfo_Keys>
<BT_BuildType>Debug</BT_BuildType>
<VerInfo_IncludeVerInfo>false</VerInfo_IncludeVerInfo>
<EnabledSysJars>activity-1.1.0.dex.jar;annotation-1.2.0.dex.jar;appcompat-1.2.0.dex.jar;appcompat-resources-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;biometric-1.1.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.1.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.1.0.dex.jar;core-runtime-2.1.0.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.2.5.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.2.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.2.0.dex.jar;lifecycle-runtime-2.2.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.2.0.dex.jar;lifecycle-viewmodel-savedstate-2.2.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;savedstate-1.0.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;vectordrawable-1.1.0.dex.jar;vectordrawable-animated-1.1.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar</EnabledSysJars>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''"> <PropertyGroup Condition="'$(Base_Win32)'!=''">
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace> <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
<BT_BuildType>Debug</BT_BuildType> <BT_BuildType>Debug</BT_BuildType>
@ -1019,6 +1041,9 @@
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/> <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
</Deployment> </Deployment>
<Platforms> <Platforms>
<Platform value="Android">False</Platform>
<Platform value="Android64">False</Platform>
<Platform value="Linux64">False</Platform>
<Platform value="Win32">True</Platform> <Platform value="Win32">True</Platform>
<Platform value="Win64">False</Platform> <Platform value="Win64">False</Platform>
</Platforms> </Platforms>

View File

@ -36,7 +36,7 @@ begin
function: IMVCDotEnv function: IMVCDotEnv
begin begin
Result := NewDotEnv Result := NewDotEnv
.WithStrategy(TMVCDotEnvPriority.FileThenEnv) .UseStrategy(TMVCDotEnvPriority.FileThenEnv)
//if available, by default, loads default environment (.env) //if available, by default, loads default environment (.env)
.UseProfile('test') //if available loads the test environment (.env.test) .UseProfile('test') //if available loads the test environment (.env.test)
.UseProfile('prod') //if available loads the prod environment (.env.prod) .UseProfile('prod') //if available loads the prod environment (.env.prod)

View File

@ -46,7 +46,7 @@ begin
function: IMVCDotEnv function: IMVCDotEnv
begin begin
Result := NewDotEnv Result := NewDotEnv
.WithStrategy(TMVCDotEnvPriority.FileThenEnv) .UseStrategy(TMVCDotEnvPriority.FileThenEnv)
//if available, by default, loads default environment (.env) //if available, by default, loads default environment (.env)
.UseProfile('test') //if available loads the test environment (.env.test) .UseProfile('test') //if available loads the test environment (.env.test)
.UseProfile('prod') //if available loads the prod environment (.env.prod) .UseProfile('prod') //if available loads the prod environment (.env.prod)

View File

@ -63,7 +63,7 @@ begin
function: IMVCDotEnv function: IMVCDotEnv
begin begin
Result := NewDotEnv Result := NewDotEnv
.WithStrategy(TMVCDotEnvPriority.FileThenEnv) .UseStrategy(TMVCDotEnvPriority.FileThenEnv)
//if available, by default, loads default environment (.env) //if available, by default, loads default environment (.env)
.UseProfile('test') //if available loads the test environment (.env.test) .UseProfile('test') //if available loads the test environment (.env.test)
.UseProfile('prod') //if available loads the prod environment (.env.prod) .UseProfile('prod') //if available loads the prod environment (.env.prod)

View File

@ -54,7 +54,7 @@ begin
function : IMVCDotEnv function : IMVCDotEnv
begin begin
Result := NewDotEnv Result := NewDotEnv
.WithStrategy(TMVCDotEnvPriority.FileThenEnv) .UseStrategy(TMVCDotEnvPriority.FileThenEnv)
.UseLogger(procedure(LogItem: String) .UseLogger(procedure(LogItem: String)
begin begin
LogW('dotEnv: ' + LogItem); LogW('dotEnv: ' + LogItem);

View File

@ -61,7 +61,7 @@ begin
function: IMVCDotEnv function: IMVCDotEnv
begin begin
Result := NewDotEnv Result := NewDotEnv
.WithStrategy(TMVCDotEnvPriority.FileThenEnv) .UseStrategy(TMVCDotEnvPriority.FileThenEnv)
.UseLogger(procedure(LogItem: String) .UseLogger(procedure(LogItem: String)
begin begin
LogW('dotEnv: ' + LogItem); LogW('dotEnv: ' + LogItem);

View File

@ -52,7 +52,7 @@ begin
function : IMVCDotEnv function : IMVCDotEnv
begin begin
Result := NewDotEnv Result := NewDotEnv
.WithStrategy(TMVCDotEnvPriority.FileThenEnv) .UseStrategy(TMVCDotEnvPriority.FileThenEnv)
//if available, by default, loads default environment (.env) //if available, by default, loads default environment (.env)
.UseProfile('test') //if available loads the test environment (.env.test) .UseProfile('test') //if available loads the test environment (.env.test)
.UseProfile('prod') //if available loads the prod environment (.env.prod) .UseProfile('prod') //if available loads the prod environment (.env.prod)

View File

@ -63,7 +63,7 @@ begin
function: IMVCDotEnv function: IMVCDotEnv
begin begin
Result := NewDotEnv Result := NewDotEnv
.WithStrategy(TMVCDotEnvPriority.FileThenEnv) .UseStrategy(TMVCDotEnvPriority.FileThenEnv)
//if available, by default, loads default environment (.env) //if available, by default, loads default environment (.env)
.UseProfile('test') //if available loads the test environment (.env.test) .UseProfile('test') //if available loads the test environment (.env.test)
.UseProfile('prod') //if available loads the prod environment (.env.prod) .UseProfile('prod') //if available loads the prod environment (.env.prod)

View File

@ -69,7 +69,7 @@ begin
function: IMVCDotEnv function: IMVCDotEnv
begin begin
Result := NewDotEnv Result := NewDotEnv
.WithStrategy(TMVCDotEnvPriority.FileThenEnv) .UseStrategy(TMVCDotEnvPriority.FileThenEnv)
//if available, by default, loads default environment (.env) //if available, by default, loads default environment (.env)
.UseProfile('test') //if available loads the test environment (.env.test) .UseProfile('test') //if available loads the test environment (.env.test)
.UseProfile('prod') //if available loads the prod environment (.env.prod) .UseProfile('prod') //if available loads the prod environment (.env.prod)

View File

@ -32,7 +32,7 @@ begin
function: IMVCDotEnv function: IMVCDotEnv
begin begin
Result := NewDotEnv Result := NewDotEnv
.WithStrategy(TMVCDotEnvPriority.FileThenEnv) .UseStrategy(TMVCDotEnvPriority.FileThenEnv)
//if available, by default, loads default environment (.env) //if available, by default, loads default environment (.env)
.UseProfile('test') //if available loads the test environment (.env.test) .UseProfile('test') //if available loads the test environment (.env.test)
.UseProfile('prod') //if available loads the prod environment (.env.prod) .UseProfile('prod') //if available loads the prod environment (.env.prod)

View File

@ -127,6 +127,11 @@ begin
else else
begin begin
DecodeJSONStrings := ''; DecodeJSONStrings := '';
if Assigned(FJSONModel) then
begin
Lua.DeclareGlobalString('__data__', FJSONModel.ToJSON());
DecodeJSONStrings := AnsiString('data') + ' = json.decode(__data__)';
end;
{ continuare da questo problema } { continuare da questo problema }
if Assigned(ViewModel) then if Assigned(ViewModel) then
begin begin
@ -138,21 +143,12 @@ begin
begin begin
lJSON.Clear; lJSON.Clear;
lSer.TValueToJSONObjectProperty(lJSON, lModelName, ViewModel[lModelName], TMVCSerializationType.stDefault, nil, nil); lSer.TValueToJSONObjectProperty(lJSON, lModelName, ViewModel[lModelName], TMVCSerializationType.stDefault, nil, nil);
// lJSONStr := lSer.SerializeCollection(ViewModel[lDataSetName]);
// if TDuckTypedList.CanBeWrappedAsList(ViewModel[lDataSetName]) then
// begin
// lJSONStr := lSer.SerializeCollection(ViewModel[lDataSetName]);
// end
// else
// begin //PODO
// lJSONStr := lSer.SerializeObject(ViewModel[lDataSetName]);
// end;
if lJSON.Values[lModelName].Typ = jdtArray then if lJSON.Values[lModelName].Typ = jdtArray then
Lua.DeclareGlobalString(lDataSetName, lJSON.A[lModelName].ToJSON()) Lua.DeclareGlobalString(lModelName, lJSON.A[lModelName].ToJSON())
else else
Lua.DeclareGlobalString(lDataSetName, lJSON.O[lModelName].ToJSON()); Lua.DeclareGlobalString(lModelName, lJSON.O[lModelName].ToJSON());
DecodeJSONStrings := DecodeJSONStrings + sLineBreak + ' ' + DecodeJSONStrings := DecodeJSONStrings + sLineBreak + ' ' +
AnsiString(lDataSetName) + ' = json.decode(' + AnsiString(lDataSetName) + ')'; AnsiString(lModelName) + ' = json.decode(' + AnsiString(lModelName) + ')';
end; end;
finally finally
lSer.Free; lSer.Free;

View File

@ -12,7 +12,7 @@ type
protected protected
procedure OnBeforeAction(Context: TWebContext; const AActionNAme: string; procedure OnBeforeAction(Context: TWebContext; const AActionNAme: string;
var Handled: Boolean); override; var Handled: Boolean); override;
procedure GeneratePeopleListAsCSV; function GeneratePeopleListAsCSV: String;
public public
[MVCPath('/people')] [MVCPath('/people')]
[MVCHTTPMethods([httpGET])] [MVCHTTPMethods([httpGET])]
@ -28,7 +28,7 @@ type
[MVCPath('/people/formats/csv')] [MVCPath('/people/formats/csv')]
[MVCHTTPMethods([httpGET])] [MVCHTTPMethods([httpGET])]
// Route usable by the browser, doesn't requires ACCEPT=text/csv // Route usable by the browser, doesn't requires ACCEPT=text/csv
procedure ExportPeopleListAsCSV; function ExportPeopleListAsCSV: String;
[MVCPath('/people')] [MVCPath('/people')]
[MVCHTTPMethods([httpPOST])] [MVCHTTPMethods([httpPOST])]
@ -43,12 +43,12 @@ type
[MVCPath('/new')] [MVCPath('/new')]
[MVCHTTPMethods([httpGET])] [MVCHTTPMethods([httpGET])]
[MVCProduces(TMVCMediaType.TEXT_HTML)] [MVCProduces(TMVCMediaType.TEXT_HTML)]
procedure NewPerson; function NewPerson: String;
[MVCPath('/edit/($guid)')] [MVCPath('/edit/($guid)')]
[MVCHTTPMethods([httpGET])] [MVCHTTPMethods([httpGET])]
[MVCProduces(TMVCMediaType.TEXT_HTML)] [MVCProduces(TMVCMediaType.TEXT_HTML)]
procedure EditPerson(guid: string); function EditPerson(guid: string): String;
[MVCPath('/')] [MVCPath('/')]
[MVCHTTPMethods([httpGET])] [MVCHTTPMethods([httpGET])]
@ -74,7 +74,7 @@ begin
Redirect('/people'); Redirect('/people');
end; end;
procedure TWebSiteController.EditPerson(guid: string); function TWebSiteController.EditPerson(guid: string): String;
var var
LDAL: IPeopleDAL; LDAL: IPeopleDAL;
lPerson: TPerson; lPerson: TPerson;
@ -92,8 +92,7 @@ begin
lItem.Selected := lPerson.Items.Contains(lItem.DeviceName); lItem.Selected := lPerson.Items.Contains(lItem.DeviceName);
end; end;
ViewData['deviceslist'] := lDevices; ViewData['deviceslist'] := lDevices;
LoadView(['header', 'editperson', 'footer']); Result := Page(['editperson']);
RenderResponseStream;
finally finally
lDevices.Free; lDevices.Free;
end; end;
@ -102,9 +101,9 @@ begin
end; end;
end; end;
procedure TWebSiteController.ExportPeopleListAsCSV; function TWebSiteController.ExportPeopleListAsCSV: String;
begin begin
GeneratePeopleListAsCSV; Result := GeneratePeopleListAsCSV;
// define the correct behaviour to download the csv inside the browser // define the correct behaviour to download the csv inside the browser
ContentType := TMVCMediaType.TEXT_CSV; ContentType := TMVCMediaType.TEXT_CSV;
Context.Response.CustomHeaders.Values['Content-Disposition'] := Context.Response.CustomHeaders.Values['Content-Disposition'] :=
@ -116,7 +115,7 @@ begin
GeneratePeopleListAsCSV; GeneratePeopleListAsCSV;
end; end;
procedure TWebSiteController.GeneratePeopleListAsCSV; function TWebSiteController.GeneratePeopleListAsCSV: String;
var var
LDAL: IPeopleDAL; LDAL: IPeopleDAL;
lPeople: TPeople; lPeople: TPeople;
@ -125,8 +124,7 @@ begin
lPeople := LDAL.GetPeople; lPeople := LDAL.GetPeople;
try try
ViewData['people'] := lPeople; ViewData['people'] := lPeople;
LoadView(['people_header.csv', 'people_list.csv']); Result := PageFragment(['people_header.csv', 'people_list.csv']);
RenderResponseStream; // rember to call RenderResponseStream!!!
finally finally
lPeople.Free; lPeople.Free;
end; end;
@ -137,7 +135,7 @@ begin
Redirect('/people'); Redirect('/people');
end; end;
procedure TWebSiteController.NewPerson; function TWebSiteController.NewPerson: String;
var var
lDAL: IPeopleDAL; lDAL: IPeopleDAL;
lDevices: TDeviceList; lDevices: TDeviceList;
@ -154,8 +152,7 @@ begin
lJSONPerson.S['last_name'] := ''; lJSONPerson.S['last_name'] := '';
lJSONPerson.S['age'] := ''; lJSONPerson.S['age'] := '';
ViewData['person'] := lJSONPerson; ViewData['person'] := lJSONPerson;
LoadView(['header', 'editperson', 'footer']); Result := PageFragment(['editperson']);
RenderResponseStream;
finally finally
lJSONPerson.Free; lJSONPerson.Free;
end; end;
@ -170,6 +167,8 @@ begin
inherited; inherited;
ContentType := 'text/html'; ContentType := 'text/html';
Handled := False; Handled := False;
SetPagesCommonHeaders(['header']);
SetPagesCommonFooters(['footer']);
end; end;
procedure TWebSiteController.PeopleList; procedure TWebSiteController.PeopleList;
@ -200,7 +199,7 @@ begin
LFirstName := Context.Request.Params['first_name'].Trim; LFirstName := Context.Request.Params['first_name'].Trim;
LLastName := Context.Request.Params['last_name'].Trim; LLastName := Context.Request.Params['last_name'].Trim;
LAge := Context.Request.Params['age']; LAge := Context.Request.Params['age'];
lDevices := Context.Request.ParamsMulti['items']; lDevices := Context.Request.ContentParamsMulti['items'];
if LFirstName.IsEmpty or LLastName.IsEmpty or LAge.IsEmpty then if LFirstName.IsEmpty or LLastName.IsEmpty or LAge.IsEmpty then
begin begin

251
tasks.py
View File

@ -12,17 +12,31 @@ from pathlib import Path
init() init()
DEFAULT_DELPHI_VERSION = "12"
g_releases_path = "releases" g_releases_path = "releases"
g_output = "bin" g_output = "bin"
g_output_folder = "" # defined at runtime g_output_folder = "" # defined at runtime
g_version = "DEV" g_version = "DEV"
def get_delphi_projects_to_build(which="", delphi_version=DEFAULT_DELPHI_VERSION):
delphi_versions = [
{"version": "10", "path": "17.0", "desc": "Delphi 10 Seattle"},
{"version": "10.1", "path": "18.0", "desc": "Delphi 10.1 Berlin"},
{"version": "10.2", "path": "19.0", "desc": "Delphi 10.2 Tokyo"},
{"version": "10.3", "path": "20.0", "desc": "Delphi 10.3 Rio"},
{"version": "10.4", "path": "21.0", "desc": "Delphi 10.4 Sydney"},
{"version": "11", "path": "22.0", "desc": "Delphi 11 Alexandria"},
{"version": "11.1", "path": "22.0", "desc": "Delphi 11.1 Alexandria"},
{"version": "11.2", "path": "22.0", "desc": "Delphi 11.2 Alexandria"},
{"version": "11.3", "path": "22.0", "desc": "Delphi 11.3 Alexandria"},
{"version": "12", "path": "23.0", "desc": "Delphi 12"},
]
def get_delphi_projects_to_build(which=""):
projects = [] projects = []
dversion = "d" + delphi_version.replace(".", "") delphi_version, _ = get_best_delphi_version_available()
dversion = "d" + delphi_version["version"].replace(".", "")
if not which or which == "core": if not which or which == "core":
projects += glob.glob( projects += glob.glob(
r"packages\{dversion}\*.groupproj".format(dversion=dversion) r"packages\{dversion}\*.groupproj".format(dversion=dversion)
@ -37,39 +51,33 @@ def get_delphi_projects_to_build(which="", delphi_version=DEFAULT_DELPHI_VERSION
return sorted(projects) return sorted(projects)
def get_best_delphi_version_available() -> (dict, str):
global delphi_version
found = False
rsvars_path = None
i = len(delphi_versions)
while (not found) and (i >= 0):
i-=1
delphi_version = delphi_versions[i]
version_path = delphi_version["path"]
rsvars_path = f"C:\\Program Files (x86)\\Embarcadero\\Studio\\{version_path}\\bin\\rsvars.bat"
if os.path.isfile(rsvars_path):
found = True
else:
rsvars_path = f"D:\\Program Files (x86)\\Embarcadero\\Studio\\{version_path}\\bin\\rsvars.bat"
if os.path.isfile(rsvars_path):
found = True
if found:
return delphi_version, rsvars_path
else:
raise Exception("Cannot find a Delphi compiler")
def build_delphi_project( def build_delphi_project(
ctx: context.Context, ctx: context.Context, project_filename, config="DEBUG", platform="Win32"
project_filename,
config="DEBUG",
delphi_version=DEFAULT_DELPHI_VERSION,
platform="Win32"
): ):
delphi_versions = { delphi_version, rsvars_path = get_best_delphi_version_available()
"10": {"path": "17.0", "desc": "Delphi 10 Seattle"},
"10.1": {"path": "18.0", "desc": "Delphi 10.1 Berlin"},
"10.2": {"path": "19.0", "desc": "Delphi 10.2 Tokyo"},
"10.3": {"path": "20.0", "desc": "Delphi 10.3 Rio"},
"10.4": {"path": "21.0", "desc": "Delphi 10.4 Sydney"},
"11": {"path": "22.0", "desc": "Delphi 11 Alexandria"},
"11.1": {"path": "22.0", "desc": "Delphi 11.1 Alexandria"},
"11.2": {"path": "22.0", "desc": "Delphi 11.2 Alexandria"},
"11.3": {"path": "22.0", "desc": "Delphi 11.3 Alexandria"},
"12": {"path": "23.0", "desc": "Delphi 12"},
}
assert delphi_version in delphi_versions, (
"Invalid Delphi version: " + delphi_version
)
print("[" + delphi_versions[delphi_version]["desc"] + "] ", end="")
version_path = delphi_versions[delphi_version]["path"]
rsvars_path = (
f"C:\\Program Files (x86)\\Embarcadero\\Studio\\{version_path}\\bin\\rsvars.bat"
)
if not os.path.isfile(rsvars_path):
rsvars_path = f"D:\\Program Files (x86)\\Embarcadero\\Studio\\{version_path}\\bin\\rsvars.bat"
if not os.path.isfile(rsvars_path):
raise Exception("Cannot find rsvars.bat")
cmdline = ( cmdline = (
'"' '"'
+ rsvars_path + rsvars_path
@ -84,7 +92,7 @@ def build_delphi_project(
if r.failed: if r.failed:
print(r.stdout) print(r.stdout)
print(r.stderr) print(r.stderr)
raise Exit("Build failed for " + delphi_versions[delphi_version]["desc"]) raise Exit("Build failed for " + delphi_version["desc"])
def zip_samples(version): def zip_samples(version):
@ -124,7 +132,7 @@ def copy_sources():
# copying tools # copying tools
print("Copying tools...") print("Copying tools...")
copytree("tools\\entitygenerator", g_output_folder + "\\tools\\entitygenerator") copytree("tools\\entitygenerator", g_output_folder + "\\tools\\entitygenerator")
# copying ideexperts # copying ideexperts
print("Copying DMVCFramework IDEExpert...") print("Copying DMVCFramework IDEExpert...")
@ -148,7 +156,7 @@ def copy_sources():
"dmvcframeworkDT.dpk", "dmvcframeworkDT.dpk",
] ]
folders = ["d100", "d101", "d102", "d103", "d104","d110","d113"] folders = ["d100", "d101", "d102", "d103", "d104", "d110", "d113"]
for folder in folders: for folder in folders:
print(f"Copying DMVCFramework Delphi {folder} packages...") print(f"Copying DMVCFramework Delphi {folder} packages...")
@ -194,7 +202,7 @@ def copy_libs(ctx):
def printkv(key, value): def printkv(key, value):
print(Fore.RESET + key + ": " + Fore.GREEN + RightValue.rjust(60) + Fore.RESET) print(Fore.RESET + key + ": " + Fore.GREEN + value.rjust(60) + Fore.RESET)
def init_build(version): def init_build(version):
@ -224,7 +232,7 @@ def init_build(version):
def build_delphi_project_list( def build_delphi_project_list(
ctx, projects, config="DEBUG", filter="", delphi_version=DEFAULT_DELPHI_VERSION ctx, projects, config="DEBUG", filter=""
): ):
ret = True ret = True
for delphi_project in projects: for delphi_project in projects:
@ -234,7 +242,7 @@ def build_delphi_project_list(
msg = f"Building: {os.path.basename(delphi_project)} ({config})" msg = f"Building: {os.path.basename(delphi_project)} ({config})"
print(Fore.RESET + msg.ljust(90, "."), end="") print(Fore.RESET + msg.ljust(90, "."), end="")
try: try:
build_delphi_project(ctx, delphi_project, "DEBUG", delphi_version) build_delphi_project(ctx, delphi_project, "DEBUG")
print(Fore.GREEN + "OK" + Fore.RESET) print(Fore.GREEN + "OK" + Fore.RESET)
except Exception as e: except Exception as e:
print(Fore.RED + "\n\nBUILD ERROR") print(Fore.RED + "\n\nBUILD ERROR")
@ -304,7 +312,7 @@ def clean(ctx, folder=None):
@task() @task()
def tests32(ctx, delphi_version=DEFAULT_DELPHI_VERSION): def tests32(ctx, delphi_version):
"""Builds and execute the unit tests""" """Builds and execute the unit tests"""
import os import os
@ -314,9 +322,13 @@ def tests32(ctx, delphi_version=DEFAULT_DELPHI_VERSION):
testserver = r"unittests\general\TestServer\TestServer.dproj" testserver = r"unittests\general\TestServer\TestServer.dproj"
print("\nBuilding Unit Test client") print("\nBuilding Unit Test client")
build_delphi_project(ctx, testclient, config="CI", delphi_version=delphi_version, platform="Win32") build_delphi_project(
ctx, testclient, config="CI", delphi_version=delphi_version, platform="Win32"
)
print("\nBuilding Test Server") print("\nBuilding Test Server")
build_delphi_project(ctx, testserver, config="CI", delphi_version=delphi_version, platform="Win32") build_delphi_project(
ctx, testserver, config="CI", delphi_version=delphi_version, platform="Win32"
)
# import subprocess # import subprocess
# subprocess.run([r"unittests\general\TestServer\Win32\Debug\TestServer.exe"]) # subprocess.run([r"unittests\general\TestServer\Win32\Debug\TestServer.exe"])
@ -339,7 +351,7 @@ def tests32(ctx, delphi_version=DEFAULT_DELPHI_VERSION):
@task() @task()
def tests64(ctx, delphi_version=DEFAULT_DELPHI_VERSION): def tests64(ctx):
"""Builds and execute the unit tests""" """Builds and execute the unit tests"""
import os import os
@ -349,9 +361,13 @@ def tests64(ctx, delphi_version=DEFAULT_DELPHI_VERSION):
testserver = r"unittests\general\TestServer\TestServer.dproj" testserver = r"unittests\general\TestServer\TestServer.dproj"
print("\nBuilding Unit Test client") print("\nBuilding Unit Test client")
build_delphi_project(ctx, testclient, config="CI", delphi_version=delphi_version, platform="Win64") build_delphi_project(
ctx, testclient, config="CI", platform="Win64"
)
print("\nBuilding Test Server") print("\nBuilding Test Server")
build_delphi_project(ctx, testserver, config="CI", delphi_version=delphi_version, platform="Win64") build_delphi_project(
ctx, testserver, config="CI", platform="Win64"
)
# import subprocess # import subprocess
# subprocess.run([r"unittests\general\TestServer\Win32\Debug\TestServer.exe"]) # subprocess.run([r"unittests\general\TestServer\Win32\Debug\TestServer.exe"])
@ -374,21 +390,26 @@ def tests64(ctx, delphi_version=DEFAULT_DELPHI_VERSION):
@task(pre=[tests32, tests64]) @task(pre=[tests32, tests64])
def tests(ctx, delphi_version=DEFAULT_DELPHI_VERSION): def tests(ctx):
pass pass
@task() @task()
def release( def release(
ctx, version="DEBUG", delphi_version=DEFAULT_DELPHI_VERSION, skip_build=False, skip_tests=False ctx,
version="DEBUG",
skip_build=False,
skip_tests=False,
): ):
"""Builds all the projects, executes integration tests and prepare the release""" """Builds all the projects, executes integration tests and prepare the release"""
init_build(version) init_build(version)
if not skip_tests: tests(ctx, delphi_version) if not skip_tests:
tests(ctx)
if not skip_build: if not skip_build:
delphi_projects = get_delphi_projects_to_build("", delphi_version) delphi_projects = get_delphi_projects_to_build("")
if not build_delphi_project_list( if not build_delphi_project_list(
ctx, delphi_projects, version, "", delphi_version ctx, delphi_projects, version, ""
): ):
return False # fails build return False # fails build
print(Fore.RESET) print(Fore.RESET)
@ -401,22 +422,22 @@ def release(
@task @task
def build_samples( def build_samples(
ctx, version="DEBUG", filter="", delphi_version=DEFAULT_DELPHI_VERSION ctx, version="DEBUG", filter=""
): ):
"""Builds samples""" """Builds samples"""
init_build(version) init_build(version)
delphi_projects = get_delphi_projects_to_build("samples", delphi_version) delphi_projects = get_delphi_projects_to_build("samples")
return build_delphi_project_list( return build_delphi_project_list(
ctx, delphi_projects, version, filter, delphi_version ctx, delphi_projects, version, filter
) )
@task(post=[]) @task(post=[])
def build_core(ctx, version="DEBUG", delphi_version=DEFAULT_DELPHI_VERSION): def build_core(ctx, version="DEBUG"):
"""Builds core packages extensions""" """Builds core packages extensions"""
init_build(version) init_build(version)
delphi_projects = get_delphi_projects_to_build("core", delphi_version) delphi_projects = get_delphi_projects_to_build("core")
ret = build_delphi_project_list(ctx, delphi_projects, version, "", delphi_version) ret = build_delphi_project_list(ctx, delphi_projects, version, "")
if not ret: if not ret:
raise Exit("Build failed") raise Exit("Build failed")
@ -437,7 +458,7 @@ def parse_template(tmpl: List[str]):
if row.upper().strip() in ["///INTERFACE.END", "///IMPLEMENTATION.END"]: if row.upper().strip() in ["///INTERFACE.END", "///IMPLEMENTATION.END"]:
if state == "parsing.interface": if state == "parsing.interface":
main_tmpl.append("$INTERFACE$") main_tmpl.append("$INTERFACE$")
if state == "parsing.implementation": if state == "parsing.implementation":
main_tmpl.append("$IMPLEMENTATION$") main_tmpl.append("$IMPLEMENTATION$")
state = "verbatim" state = "verbatim"
continue continue
@ -465,22 +486,70 @@ def generate_nullables(ctx):
main_tmpl, intf_tmpl, impl_tmpl = parse_template(rows) main_tmpl, intf_tmpl, impl_tmpl = parse_template(rows)
delphi_types = [ delphi_types = [
["String", "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and \n\t (LeftValue.Value = RightValue.Value))"], [
["Currency", "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and \n\t (LeftValue.Value = RightValue.Value))"], "String",
["Boolean", "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and \n\t (LeftValue.Value = RightValue.Value))"], "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and \n\t (LeftValue.Value = RightValue.Value))",
["TDate", "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and \n\t (DateToISODate(LeftValue.Value) = DateToISODate(RightValue.Value)))"], ],
["TTime", "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and \n\t (TimeToISOTime(LeftValue.Value) = TimeToISOTime(RightValue.Value)))"], [
["TDateTime", "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and \n\t (DateTimeToISOTimeStamp(LeftValue.Value) = DateTimeToISOTimeStamp(RightValue.Value)))"], "Currency",
["Single", "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and \n\t SameValue(LeftValue.Value, RightValue.Value, 0.000001))"], "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and \n\t (LeftValue.Value = RightValue.Value))",
["Double", "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and \n\t SameValue(LeftValue.Value, RightValue.Value, 0.000000001))"], ],
["Extended", "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and \n\t SameValue(LeftValue.Value, RightValue.Value, 0.000000001))"], [
["Int16", "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and (LeftValue.Value = RightValue.Value))"], "Boolean",
["UInt16", "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and (LeftValue.Value = RightValue.Value))"], "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and \n\t (LeftValue.Value = RightValue.Value))",
["Int32", "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and (LeftValue.Value = RightValue.Value))"], ],
["UInt32", "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and (LeftValue.Value = RightValue.Value))"], [
["Int64", "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and (LeftValue.Value = RightValue.Value))"], "TDate",
["UInt64", "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and (LeftValue.Value = RightValue.Value))"], "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and \n\t (DateToISODate(LeftValue.Value) = DateToISODate(RightValue.Value)))",
["TGUID", "(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and (LeftValue.Value = RightValue.Value))"], ],
[
"TTime",
"(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and \n\t (TimeToISOTime(LeftValue.Value) = TimeToISOTime(RightValue.Value)))",
],
[
"TDateTime",
"(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and \n\t (DateTimeToISOTimeStamp(LeftValue.Value) = DateTimeToISOTimeStamp(RightValue.Value)))",
],
[
"Single",
"(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and \n\t SameValue(LeftValue.Value, RightValue.Value, 0.000001))",
],
[
"Double",
"(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and \n\t SameValue(LeftValue.Value, RightValue.Value, 0.000000001))",
],
[
"Extended",
"(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and \n\t SameValue(LeftValue.Value, RightValue.Value, 0.000000001))",
],
[
"Int16",
"(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and (LeftValue.Value = RightValue.Value))",
],
[
"UInt16",
"(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and (LeftValue.Value = RightValue.Value))",
],
[
"Int32",
"(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and (LeftValue.Value = RightValue.Value))",
],
[
"UInt32",
"(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and (LeftValue.Value = RightValue.Value))",
],
[
"Int64",
"(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and (LeftValue.Value = RightValue.Value))",
],
[
"UInt64",
"(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and (LeftValue.Value = RightValue.Value))",
],
[
"TGUID",
"(LeftValue.IsNull and RightValue.IsNull) or ((LeftValue.HasValue and RightValue.HasValue) and (LeftValue.Value = RightValue.Value))",
],
] ]
str_main_tmpl = "".join(main_tmpl) str_main_tmpl = "".join(main_tmpl)
@ -493,23 +562,31 @@ def generate_nullables(ctx):
enum_declaration = ["ntInvalidNullableType"] enum_declaration = ["ntInvalidNullableType"]
enum_detect_line = [] enum_detect_line = []
for delphi_type, type_compare in delphi_types: for delphi_type, type_compare in delphi_types:
enum_declaration.append('ntNullable' + delphi_type) enum_declaration.append("ntNullable" + delphi_type)
enum_detect_line.append(f" if aTypeInfo = TypeInfo(Nullable{delphi_type}) then \n Exit(ntNullable{delphi_type}); ") enum_detect_line.append(
f" if aTypeInfo = TypeInfo(Nullable{delphi_type}) then \n Exit(ntNullable{delphi_type}); "
)
intf_out += ( intf_out += (
f"//**************************\n// ** Nullable{delphi_type}\n//**************************\n\n" f"//**************************\n// ** Nullable{delphi_type}\n//**************************\n\n"
+ str_intf_tmpl.replace("$TYPE$", delphi_type) + str_intf_tmpl.replace("$TYPE$", delphi_type)
) )
impl_out += str_impl_tmpl \ impl_out += (
.replace("$TYPE$", delphi_type) \ str_impl_tmpl.replace("$TYPE$", delphi_type).replace(
.replace("$COMPARE$", type_compare) + "\n" "$COMPARE$", type_compare
)
+ "\n"
)
enum_declaration = (
enum_declaration = ' TNullableType = (\n ' + '\n , '.join(enum_declaration) + ');\n\n' " TNullableType = (\n " + "\n , ".join(enum_declaration) + ");\n\n"
)
enum_detect_function = [] enum_detect_function = []
enum_detect_function.append("function GetNullableType(const aTypeInfo: PTypeInfo): TNullableType;") enum_detect_function.append(
"function GetNullableType(const aTypeInfo: PTypeInfo): TNullableType;"
)
enum_detect_function.append("begin") enum_detect_function.append("begin")
enum_detect_function.extend(enum_detect_line) enum_detect_function.extend(enum_detect_line)
enum_detect_function.append(" Result := ntInvalidNullableType;") enum_detect_function.append(" Result := ntInvalidNullableType;")
enum_detect_function.append("end;") enum_detect_function.append("end;")
@ -517,10 +594,12 @@ def generate_nullables(ctx):
intf_out += enum_detect_function[0] + "\n" intf_out += enum_detect_function[0] + "\n"
impl_out += "\n".join(enum_detect_function) + "\n" impl_out += "\n".join(enum_detect_function) + "\n"
str_main_tmpl = str_main_tmpl \ str_main_tmpl = (
.replace("$INTERFACE$", intf_out) \ str_main_tmpl.replace("$INTERFACE$", intf_out).replace(
.replace("$IMPLEMENTATION$", impl_out) \ "$IMPLEMENTATION$", impl_out
)
+ "\n" + "\n"
)
with open(output_unitname, "w") as f: with open(output_unitname, "w") as f:
f.writelines(str_main_tmpl) f.writelines(str_main_tmpl)