Quick.Options.Serializer.Yaml.pas 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. { ***************************************************************************
  2. Copyright (c) 2015-2020 Kike Pérez
  3. Unit : Quick.Options.Serializer.Yaml
  4. Description : Configuration groups Yaml Serializer
  5. Author : Kike Pérez
  6. Version : 1.0
  7. Created : 18/10/2019
  8. Modified : 15/12/2021
  9. This file is part of QuickLib: https://github.com/exilon/QuickLib
  10. ***************************************************************************
  11. Licensed under the Apache License, Version 2.0 (the "License");
  12. you may not use this file except in compliance with the License.
  13. You may obtain a copy of the License at
  14. http://www.apache.org/licenses/LICENSE-2.0
  15. Unless required by applicable law or agreed to in writing, software
  16. distributed under the License is distributed on an "AS IS" BASIS,
  17. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. See the License for the specific language governing permissions and
  19. limitations under the License.
  20. *************************************************************************** }
  21. unit Quick.Options.Serializer.Yaml;
  22. {$i QuickLib.inc}
  23. interface
  24. uses
  25. System.SysUtils,
  26. System.IOUtils,
  27. System.Generics.Collections,
  28. Quick.YAML,
  29. Quick.Commons,
  30. Quick.YAML.Serializer,
  31. Quick.Options;
  32. type
  33. TYamlOptionsSerializer = class(TOptionsFileSerializer)
  34. private
  35. fSerializer : TRTTIYaml;
  36. function ParseFile(out aYamlObj : TYamlObject) : Boolean;
  37. public
  38. constructor Create(const aFilename : string);
  39. destructor Destroy; override;
  40. function Load(aSections : TSectionList; aFailOnSectionNotExists : Boolean) : Boolean; override;
  41. function LoadSection(aSections : TSectionList; aOptions: TOptions) : Boolean; override;
  42. procedure Save(aSections : TSectionList); override;
  43. function GetFileSectionNames(out oSections : TArray<string>) : Boolean; override;
  44. function ConfigExists : Boolean; override;
  45. end;
  46. implementation
  47. { TYamlOptionsSerializer }
  48. function TYamlOptionsSerializer.ConfigExists: Boolean;
  49. begin
  50. Result := FileExists(Filename);
  51. end;
  52. constructor TYamlOptionsSerializer.Create(const aFilename : string);
  53. begin
  54. Filename := aFilename;
  55. fSerializer := TRTTIYaml.Create(TSerializeLevel.slPublishedProperty,True);
  56. end;
  57. destructor TYamlOptionsSerializer.Destroy;
  58. begin
  59. fSerializer.Free;
  60. inherited;
  61. end;
  62. function TYamlOptionsSerializer.GetFileSectionNames(out oSections : TArray<string>) : Boolean;
  63. var
  64. yaml : TYamlObject;
  65. i : Integer;
  66. begin
  67. Result := False;
  68. yaml := nil;
  69. if ParseFile(yaml) then
  70. begin
  71. try
  72. for i := 0 to yaml.Count - 1 do
  73. begin
  74. oSections := oSections + [yaml.Pairs[i].Name];
  75. end;
  76. Result := True;
  77. finally
  78. yaml.Free;
  79. end;
  80. end;
  81. end;
  82. function TYamlOptionsSerializer.ParseFile(out aYamlObj : TYamlObject) : Boolean;
  83. var
  84. fileoptions : string;
  85. begin
  86. aYamlObj := nil;
  87. if FileExists(Filename) then
  88. begin
  89. fileoptions := TFile.ReadAllText(Filename,TEncoding.UTF8);
  90. if fileoptions.IsEmpty then EOptionLoadError.CreateFmt('Config file "%s" is empty!',[ExtractFileName(Filename)]);
  91. aYamlObj := TYamlObject.ParseYAMLValue(fileoptions) as TYamlObject;
  92. if aYamlObj = nil then raise EOptionLoadError.CreateFmt('Config file "%s" is damaged or not well-formed Yaml format!',[ExtractFileName(Filename)]);
  93. end;
  94. Result := aYamlObj <> nil;
  95. end;
  96. function TYamlOptionsSerializer.Load(aSections : TSectionList; aFailOnSectionNotExists : Boolean) : Boolean;
  97. var
  98. option : TOptions;
  99. yaml : TYamlObject;
  100. ypair : TYamlPair;
  101. found : Integer;
  102. begin
  103. Result := False;
  104. //read option file
  105. if ParseFile(yaml) then
  106. begin
  107. found := 0;
  108. try
  109. for option in aSections do
  110. begin
  111. ypair := fSerializer.GetYamlPairByName(yaml,option.Name);
  112. if ypair = nil then
  113. begin
  114. if aFailOnSectionNotExists then raise Exception.CreateFmt('Config section "%s" not found',[option.Name])
  115. else
  116. begin
  117. //count as found if hidden
  118. if option.HideOptions then Inc(found);
  119. Continue;
  120. end;
  121. end;
  122. if ypair.Value <> nil then
  123. begin
  124. //deserialize option
  125. fSerializer.DeserializeObject(option,ypair.Value as TYamlObject);
  126. //validate loaded configuration
  127. option.ValidateOptions;
  128. Inc(found);
  129. end;
  130. end;
  131. finally
  132. yaml.Free;
  133. end;
  134. //returns true if all sections located into file
  135. Result := found = aSections.Count;
  136. end;
  137. end;
  138. function TYamlOptionsSerializer.LoadSection(aSections : TSectionList; aOptions: TOptions) : Boolean;
  139. var
  140. yaml : TYamlObject;
  141. ypair : TYamlPair;
  142. begin
  143. Result := False;
  144. //read option file
  145. if ParseFile(yaml) then
  146. begin
  147. try
  148. ypair := fSerializer.GetYamlPairByName(yaml,aOptions.Name);
  149. if (ypair <> nil) and (ypair.Value <> nil) then
  150. begin
  151. //deserialize option
  152. fSerializer.DeserializeObject(aOptions,ypair.Value as TYamlObject);
  153. //validate loaded configuration
  154. aOptions.ValidateOptions;
  155. Result := True;
  156. end
  157. finally
  158. yaml.Free;
  159. end;
  160. end;
  161. end;
  162. procedure TYamlOptionsSerializer.Save(aSections : TSectionList);
  163. var
  164. option : TOptions;
  165. fileoptions : string;
  166. yaml : TYamlObject;
  167. jpair : TYamlPair;
  168. begin
  169. yaml := TYamlObject.Create;
  170. try
  171. for option in aSections do
  172. begin
  173. if not option.HideOptions then
  174. begin
  175. //validate configuration before save
  176. option.ValidateOptions;
  177. //serialize option
  178. jpair := fSerializer.Serialize(option.Name,option);
  179. yaml.AddPair(jpair);
  180. end;
  181. end;
  182. fileoptions := yaml.ToYaml;
  183. if not fileoptions.IsEmpty then TFile.WriteAllText(Filename,fileoptions);
  184. finally
  185. yaml.Free;
  186. end;
  187. end;
  188. end.