pkghandler.pp 7.9 KB

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