2
0

pkghandler.pp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. {$mode objfpc}
  2. {$h+}
  3. unit pkghandler;
  4. {$IFDEF OS2}
  5. {$DEFINE NO_UNIT_PROCESS}
  6. {$ENDIF OS2}
  7. {$IFDEF GO32V2}
  8. {$DEFINE NO_UNIT_PROCESS}
  9. {$ENDIF GO32V2}
  10. {$ifndef NO_UNIT_PROCESS}
  11. {$define HAS_UNIT_PROCESS}
  12. {$endif NO_UNIT_PROCESS}
  13. interface
  14. uses
  15. Classes,SysUtils,
  16. pkgglobals,
  17. pkgoptions,
  18. {$ifdef HAS_UNIT_PROCESS}
  19. process,
  20. {$endif HAS_UNIT_PROCESS}
  21. fprepos,
  22. pkgFppkg;
  23. type
  24. { TPackageHandler }
  25. TPackageHandler = Class(TComponent)
  26. private
  27. FPackageName : string;
  28. FPackageManager: tpkgFPpkg;
  29. Protected
  30. Procedure Log(Level: TLogLevel;Msg : String);
  31. Procedure Log(Level: TLogLevel;Fmt : String; const Args : array of const);
  32. Procedure Error(Msg : String);
  33. Procedure Error(Fmt : String; const Args : array of const);
  34. Function ExecuteProcess(Const Prog,Args:String):Integer;
  35. Procedure SetCurrentDir(Const ADir:String);
  36. Property PackageManager:TpkgFPpkg Read FPackageManager;
  37. Public
  38. Constructor Create(AOwner:TComponent; APackageManager:TpkgFPpkg; const APackageName:string); virtual;
  39. function PackageLogPrefix:String;
  40. procedure ExecuteAction(const APackageName,AAction:string);
  41. procedure Execute; virtual; abstract;
  42. Property PackageName:string Read FPackageName;
  43. end;
  44. TPackageHandlerClass = class of TPackageHandler;
  45. EPackageHandler = Class(Exception);
  46. // Actions/PkgHandler
  47. procedure RegisterPkgHandler(const AAction:string;pkghandlerclass:TPackageHandlerClass);
  48. function GetPkgHandler(const AAction:string):TPackageHandlerClass;
  49. procedure ExecuteAction(const APackageName,AAction:string; PackageManager: TpkgFPpkg);
  50. function PackageBuildPath(APackage:TFPPackage):String;
  51. function PackageRemoteArchive(APackage:TFPPackage): String;
  52. function PackageLocalArchive(APackage:TFPPackage): String;
  53. function PackageManifestFile(APackage:TFPPackage): String;
  54. procedure ClearExecutedAction;
  55. Implementation
  56. uses
  57. typinfo,
  58. contnrs,
  59. uriparser,
  60. pkgrepos,
  61. pkgmessages;
  62. var
  63. PkgHandlerList : TFPHashList;
  64. ExecutedActions : TFPHashList;
  65. CurrentDir : string;
  66. procedure RegisterPkgHandler(const AAction:string;pkghandlerclass:TPackageHandlerClass);
  67. begin
  68. if PkgHandlerList.Find(AAction)<>nil then
  69. begin
  70. Raise EPackageHandler.CreateFmt(SErrActionAlreadyRegistered,[AAction]);
  71. exit;
  72. end;
  73. PkgHandlerList.Add(AAction,pkghandlerclass);
  74. end;
  75. function GetPkgHandler(const AAction:string):TPackageHandlerClass;
  76. begin
  77. result:=TPackageHandlerClass(PkgHandlerList.Find(AAction));
  78. if result=nil then
  79. Raise EPackageHandler.CreateFmt(SErrActionNotFound,[AAction]);
  80. end;
  81. procedure ExecuteAction(const APackageName,AAction:string; PackageManager: TpkgFPpkg);
  82. var
  83. pkghandlerclass : TPackageHandlerClass;
  84. FullActionName : string;
  85. begin
  86. // Check if we have already executed or are executing the action
  87. FullActionName:=APackageName+AAction;
  88. if ExecutedActions.Find(FullActionName)<>nil then
  89. begin
  90. Log(llDebug,'Already executed or executing action '+FullActionName);
  91. exit;
  92. end;
  93. ExecutedActions.Add(FullActionName,Pointer(PtrUInt(1)));
  94. // Create action handler class
  95. pkghandlerclass:=GetPkgHandler(AAction);
  96. With pkghandlerclass.Create(nil,PackageManager,APackageName) do
  97. try
  98. Log(llDebug,SLogRunAction+' start',[AAction]);
  99. Execute;
  100. Log(llDebug,SLogRunAction+' end',[AAction]);
  101. finally
  102. Free;
  103. end;
  104. end;
  105. function PackageBuildPath(APackage:TFPPackage):String;
  106. begin
  107. if (APackage.Name=CmdLinePackageName) or (APackage.Name=URLPackageName) then
  108. Result:=GFPpkg.Options.GlobalSection.BuildDir+ChangeFileExt(ExtractFileName(APackage.LocalFileName),'')
  109. else if Assigned(APackage.PackagesStructure) and (APackage.PackagesStructure.GetBuildPathDirectory(APackage)<>'') then
  110. Result:=APackage.PackagesStructure.GetBuildPathDirectory(APackage)
  111. else
  112. Result:=GFPpkg.Options.GlobalSection.BuildDir+APackage.Name;
  113. end;
  114. function PackageRemoteArchive(APackage:TFPPackage): String;
  115. begin
  116. if APackage.Name=CurrentDirPackageName then
  117. Error(SErrNoPackageSpecified)
  118. else if APackage.Name=CmdLinePackageName then
  119. Error(SErrPackageIsLocal);
  120. if APackage.DownloadURL<>'' then
  121. Result:=APackage.DownloadURL
  122. else
  123. Result:=GetRemoteRepositoryURL(APackage.FileName);
  124. end;
  125. function PackageLocalArchive(APackage:TFPPackage): String;
  126. begin
  127. if APackage.Name=CurrentDirPackageName then
  128. Error(SErrNoPackageSpecified)
  129. else if APackage.Name=CmdLinePackageName then
  130. Result:=APackage.LocalFileName
  131. else
  132. Result:=GFPpkg.Options.GlobalSection.ArchivesDir+APackage.FileName;
  133. end;
  134. function PackageManifestFile(APackage:TFPPackage): String;
  135. begin
  136. Result:=ManifestFileName;
  137. end;
  138. procedure ClearExecutedAction;
  139. begin
  140. ExecutedActions.Clear;
  141. end;
  142. { TPackageHandler }
  143. Constructor TPackageHandler.Create(AOwner: TComponent; APackageManager: TpkgFPpkg;
  144. const APackageName: string);
  145. begin
  146. inherited Create(AOwner);
  147. FPackageName:=APackageName;
  148. FPackageManager:=APackageManager;
  149. end;
  150. {$ifdef HAS_UNIT_PROCESS}
  151. function ExecuteFPC(const Path: string; const ComLine: string): integer;
  152. var
  153. P: TProcess;
  154. ConsoleOutput: TMemoryStream;
  155. BytesRead: longint;
  156. function ReadFromStream: longint;
  157. const
  158. READ_BYTES = 2048;
  159. var
  160. n: longint;
  161. BuffPos: longint;
  162. sLine: string;
  163. ch: char;
  164. begin
  165. // make sure we have room
  166. ConsoleOutput.SetSize(BytesRead + READ_BYTES);
  167. // try reading it
  168. n := P.Output.Read((ConsoleOutput.Memory + BytesRead)^, READ_BYTES);
  169. if n > 0 then
  170. begin
  171. Inc(BytesRead, n);
  172. sLine := '';
  173. BuffPos := ConsoleOutput.Position;
  174. //read lines from the stream
  175. repeat
  176. ConsoleOutput.Read(ch,1);
  177. if ch in [#10, #13] then
  178. begin
  179. log(llProgres,sLine);
  180. sLine := '';
  181. BuffPos := ConsoleOutput.Position;
  182. end
  183. else
  184. sLine := sLine + ch;
  185. until ConsoleOutput.Position >= BytesRead;
  186. ConsoleOutput.Position := BuffPos;
  187. end
  188. else
  189. begin
  190. // no data, wait 100 ms
  191. Sleep(100);
  192. end;
  193. Result := n;
  194. end;
  195. begin
  196. result := -1;
  197. BytesRead := 0;
  198. ConsoleOutput := TMemoryStream.Create;
  199. try
  200. P := TProcess.Create(nil);
  201. try
  202. P.CommandLine := Path + ' ' + ComLine;
  203. P.Options := [poUsePipes];
  204. P.Execute;
  205. while P.Running do
  206. ReadFromStream;
  207. // read last part
  208. repeat
  209. until ReadFromStream = 0;
  210. ConsoleOutput.SetSize(BytesRead);
  211. result := P.ExitStatus;
  212. finally
  213. P.Free;
  214. end;
  215. finally
  216. ConsoleOutput.Free;
  217. end;
  218. end;
  219. {$endif HAS_UNIT_PROCESS}
  220. Function TPackageHandler.ExecuteProcess(Const Prog,Args:String):Integer;
  221. begin
  222. Log(llCommands,SLogExecute,[Prog,Args]);
  223. Flush(StdOut);
  224. {$ifdef HAS_UNIT_PROCESS}
  225. Result:=ExecuteFPC(Prog,Args);
  226. {$else HAS_UNIT_PROCESS}
  227. Result:=SysUtils.ExecuteProcess(Prog,Args);
  228. {$endif HAS_UNIT_PROCESS}
  229. end;
  230. Procedure TPackageHandler.SetCurrentDir(Const ADir:String);
  231. begin
  232. Log(llCommands,SLogChangeDir,[ADir]);
  233. if not SysUtils.SetCurrentDir(ADir) then
  234. Error(SErrChangeDirFailed,[ADir]);
  235. end;
  236. function TPackageHandler.PackageLogPrefix:String;
  237. begin
  238. if PackageName<>'' then
  239. Result:='['+PackageName+'] '
  240. else
  241. Result:='';
  242. end;
  243. procedure TPackageHandler.ExecuteAction(const APackageName,AAction:string);
  244. begin
  245. pkghandler.ExecuteAction(APackageName,AAction,PackageManager);
  246. end;
  247. Procedure TPackageHandler.Log(Level:TLogLevel; Msg:String);
  248. begin
  249. pkgglobals.Log(Level,PackageLogPrefix+Msg);
  250. end;
  251. Procedure TPackageHandler.Log(Level:TLogLevel; Fmt:String; const Args:array of const);
  252. begin
  253. pkgglobals.log(Level,PackageLogPrefix+Fmt,Args);
  254. end;
  255. Procedure TPackageHandler.Error(Msg:String);
  256. begin
  257. pkgglobals.Error(PackageLogPrefix+Msg);
  258. end;
  259. Procedure TPackageHandler.Error(Fmt:String; const Args:array of const);
  260. begin
  261. pkgglobals.Error(PackageLogPrefix+Fmt,Args);
  262. end;
  263. initialization
  264. PkgHandlerList:=TFPHashList.Create;
  265. ExecutedActions:=TFPHashList.Create;
  266. finalization
  267. FreeAndNil(PkgHandlerList);
  268. FreeAndNil(ExecutedActions);
  269. end.