pkgglobals.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. {$mode objfpc}
  2. {$h+}
  3. unit pkgglobals;
  4. interface
  5. uses
  6. {$ifdef unix}
  7. baseunix,
  8. {$endif}
  9. SysUtils,
  10. Classes,
  11. fpmkunit;
  12. Const
  13. {$ifdef unix}
  14. ExeExt = '';
  15. AllFiles='*';
  16. {$else unix}
  17. ExeExt = '.exe';
  18. AllFiles='*.*';
  19. {$endif unix}
  20. Type
  21. TFPMKUnitDep=record
  22. package : string[64];
  23. reqver : string[8];
  24. undef : string[32];
  25. def : string[32];
  26. PluginUnit : string[64];
  27. available : boolean;
  28. end;
  29. Const
  30. CmdLinePackageName='<cmdline>';
  31. CurrentDirPackageName='<currentdir>';
  32. URLPackageName='<url>';
  33. // Dependencies for compiling the fpmkunit unit
  34. FPMKUnitDepDefaultCount=5;
  35. FPMKUnitDepsDefaults : array[0..FPMKUnitDepDefaultCount-1] of TFPMKUnitDep = (
  36. (package: 'hash';
  37. reqver : '2.2.2';
  38. undef : 'NO_UNIT_ZIPPER'),
  39. (package: 'paszlib';
  40. reqver : '2.2.2';
  41. undef : 'NO_UNIT_ZIPPER'),
  42. (package: 'fcl-process';
  43. reqver : '2.2.2';
  44. undef : 'NO_UNIT_PROCESS'),
  45. (package: 'libtar';
  46. reqver : '2.7.1';
  47. undef : 'NO_TAR_SUPPORT'),
  48. (package: 'fpmkunit';
  49. reqver : '2.2.2-1';
  50. undef : '')
  51. );
  52. Type
  53. TLogLevel = (llError,llWarning,llInfo,llCommands,llDebug,llProgress);
  54. TLogLevels = Set of TLogLevel;
  55. TLogProc = procedure(Level:TLogLevel;Const Msg: String);
  56. const
  57. DefaultLogLevels = [llError,llWarning, llProgress];
  58. AllLogLevels = [llError,llWarning,llCommands,llInfo,llProgress];
  59. type
  60. EPackagerError = class(Exception);
  61. TPkgErrorProc = Procedure(Const Msg : String);
  62. // Logging
  63. Function StringToLogLevels (S : String) : TLogLevels;
  64. Function LogLevelsToString (V : TLogLevels): String;
  65. Procedure log(Level:TLogLevel; Const Fmt:String; const Args:array of const);
  66. Procedure log(Level:TLogLevel; Const Msg:String);
  67. Procedure Error(Const Fmt : String; const Args : array of const);
  68. Procedure Error(Const Msg : String);
  69. // Utils
  70. function maybequoted(const s:string):string;
  71. Function FixPath(const S : String) : string; inline; deprecated 'Use fpmkunit.FixPath instead';
  72. Function DirectoryExistsLog(const ADir:string):Boolean;
  73. Function FileExistsLog(const AFileName:string):Boolean;
  74. procedure BackupFile(const AFileName: String);
  75. Procedure DeleteDir(const ADir:string);
  76. Procedure SearchFiles(SL:TStringList;const APattern:string);
  77. Function GetCompilerInfo(const ACompiler,AOptions:string):string; overload;
  78. Procedure GetCompilerInfo(const ACompiler, AOptions: string; out AVersion: string; out ACPU: TCpu; out aOS:TOS); overload;
  79. function IsSuperUser:boolean;
  80. procedure ReadIniFile(Const AFileName: String;L:TStrings);
  81. var
  82. LogLevels : TLogLevels;
  83. FPMKUnitDeps : array of TFPMKUnitDep;
  84. LogHandler: TLogProc;
  85. ErrorHandler: TPkgErrorProc;
  86. function GetFppkgConfigFile(Global : Boolean; SubDir : Boolean): string;
  87. function GetFppkgConfigDir(Global : Boolean): string;
  88. Implementation
  89. // define use_shell to use sysutils.executeprocess
  90. // as alternate to using 'process' in getcompilerinfo
  91. {$IF defined(GO32v2) or defined(WATCOM) or defined(OS2)}
  92. {$DEFINE USE_SHELL}
  93. {$ENDIF GO32v2 or WATCOM or OS2}
  94. uses
  95. typinfo,
  96. {$IFNDEF USE_SHELL}
  97. process,
  98. {$ENDIF USE_SHELL}
  99. contnrs,
  100. uriparser,
  101. pkgmessages;
  102. function FPPkgGetVendorName:string;
  103. begin
  104. {$ifdef unix}
  105. result:='fpc';
  106. {$else}
  107. result:='FreePascal'
  108. {$endif}
  109. end;
  110. function FPPkgGetApplicationName:string;
  111. begin
  112. result:='fppkg';
  113. end;
  114. function StringToLogLevels(S: String): TLogLevels;
  115. Var
  116. I : integer;
  117. begin
  118. I:=GetEnumValue(TypeInfo(TLogLevels),'v'+S);
  119. If (I<>-1) then
  120. Result:=TLogLevels(I)
  121. else
  122. Raise EPackagerError.CreateFmt(SErrInvalidLogLevels,[S]);
  123. end;
  124. Function LogLevelsToString (V : TLogLevels): String;
  125. begin
  126. Result:=GetEnumName(TypeInfo(TLogLevels),Integer(V));
  127. Delete(Result,1,1);// Delete 'v'
  128. end;
  129. procedure LogCmd(Level:TLogLevel; Const Msg: String);
  130. var
  131. Prefix : string;
  132. begin
  133. if not(Level in LogLevels) then
  134. exit;
  135. Prefix:='';
  136. case Level of
  137. llWarning :
  138. Prefix:=SWarning;
  139. llError :
  140. Prefix:=SError;
  141. { llInfo :
  142. Prefix:='I: ';
  143. llCommands :
  144. Prefix:='C: ';
  145. llDebug :
  146. Prefix:='D: '; }
  147. end;
  148. Writeln(stdOut,Prefix,Msg);
  149. end;
  150. procedure ErrorCmd(Const Msg: String);
  151. begin
  152. Raise EPackagerError.Create(Msg);
  153. end;
  154. Procedure log(Level:TLogLevel; Const Msg : String);
  155. begin
  156. Loghandler(level,Msg)
  157. end;
  158. Procedure log(Level:TLogLevel; Const Fmt:String; const Args:array of const);
  159. begin
  160. LogHandler(Level,Format(Fmt,Args));
  161. end;
  162. Procedure Error(Const Msg : String);
  163. begin
  164. ErrorHandler(Msg)
  165. end;
  166. procedure Error(Const Fmt: String; const Args: array of const);
  167. begin
  168. ErrorHandler(Format(Fmt, Args));
  169. end;
  170. function maybequoted(const s:string):string;
  171. const
  172. {$IFDEF MSWINDOWS}
  173. FORBIDDEN_CHARS = ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
  174. '{', '}', '''', '`', '~'];
  175. {$ELSE}
  176. FORBIDDEN_CHARS = ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
  177. '{', '}', '''', ':', '\', '`', '~'];
  178. {$ENDIF}
  179. var
  180. s1 : string;
  181. i : integer;
  182. quoted : boolean;
  183. begin
  184. quoted:=false;
  185. s1:='"';
  186. for i:=1 to length(s) do
  187. begin
  188. case s[i] of
  189. '"' :
  190. begin
  191. quoted:=true;
  192. s1:=s1+'\"';
  193. end;
  194. ' ',
  195. #128..#255 :
  196. begin
  197. quoted:=true;
  198. s1:=s1+s[i];
  199. end;
  200. else begin
  201. if s[i] in FORBIDDEN_CHARS then
  202. quoted:=True;
  203. s1:=s1+s[i];
  204. end;
  205. end;
  206. end;
  207. if quoted then
  208. maybequoted:=s1+'"'
  209. else
  210. maybequoted:=s;
  211. end;
  212. Function FixPath(const S : String) : string;
  213. begin
  214. Result:=fpmkunit.FixPath(S, True);
  215. end;
  216. Function DirectoryExistsLog(const ADir:string):Boolean;
  217. begin
  218. result:=SysUtils.DirectoryExists(ADir);
  219. if result then
  220. log(llDebug,SDbgDirectoryExists,[ADir,SDbgFound])
  221. else
  222. log(llDebug,SDbgDirectoryExists,[ADir,SDbgNotFound]);
  223. end;
  224. Function FileExistsLog(const AFileName:string):Boolean;
  225. begin
  226. result:=SysUtils.FileExists(AFileName);
  227. if result then
  228. log(llDebug,SDbgFileExists,[AFileName,SDbgFound])
  229. else
  230. log(llDebug,SDbgFileExists,[AFileName,SDbgNotFound]);
  231. end;
  232. procedure BackupFile(const AFileName: String);
  233. Var
  234. BFN : String;
  235. begin
  236. BFN:=AFileName+'.bak';
  237. log(llDebug,SDbgBackupFile,[BFN]);
  238. If not RenameFile(AFileName,BFN) then
  239. Error(SErrBackupFailed,[AFileName,BFN]);
  240. end;
  241. Procedure DeleteDir(const ADir:string);
  242. var
  243. Info : TSearchRec;
  244. begin
  245. // Prevent accidently deleting all files in current or root dir
  246. if (ADir='') or (ADir=PathDelim) then
  247. exit;
  248. if FindFirst(ADir+PathDelim+AllFiles,faAnyFile, Info)=0 then
  249. try
  250. repeat
  251. if (Info.Attr and faDirectory)=faDirectory then
  252. begin
  253. if (Info.Name<>'.') and (Info.Name<>'..') then
  254. DeleteDir(ADir+PathDelim+Info.Name)
  255. end
  256. else
  257. DeleteFile(ADir+PathDelim+Info.Name);
  258. until FindNext(Info)<>0;
  259. finally
  260. FindClose(Info);
  261. end;
  262. RemoveDir(Adir);
  263. end;
  264. Procedure SearchFiles(SL:TStringList;const APattern:string);
  265. var
  266. Info : TSearchRec;
  267. ADir : string;
  268. begin
  269. ADir:=ExtractFilePath(APattern);
  270. if FindFirst(APattern,faAnyFile, Info)=0 then
  271. try
  272. repeat
  273. if (Info.Attr and faDirectory)=faDirectory then
  274. begin
  275. if (Info.Name<>'.') and (Info.Name<>'..') then
  276. SearchFiles(SL,ADir+Info.Name+PathDelim+ExtractFileName(APattern))
  277. end;
  278. SL.Add(ADir+Info.Name);
  279. until FindNext(Info)<>0;
  280. finally
  281. FindClose(Info);
  282. end;
  283. end;
  284. //
  285. // if use_shell defined uses sysutils.executeprocess else uses 'process'
  286. //
  287. function GetCompilerInfo(const ACompiler,AOptions:string):string;
  288. const
  289. BufSize = 1024;
  290. var
  291. {$IFDEF USE_SHELL}
  292. TmpFileName, ProcIDStr: shortstring;
  293. TmpFile: file;
  294. CmdLine2: string;
  295. {$ELSE USE_SHELL}
  296. S: TProcess;
  297. {$ENDIF USE_SHELL}
  298. Buf: array [0..BufSize - 1] of char;
  299. Count: longint;
  300. begin
  301. {$IFDEF USE_SHELL}
  302. Str (GetProcessID, ProcIDStr);
  303. TmpFileName := GetEnvironmentVariable ('TEMP');
  304. if TmpFileName <> '' then
  305. TmpFileName := TmpFileName + DirectorySeparator + 'fppkgout.' + ProcIDStr
  306. else
  307. TmpfileName := 'fppkgout.' + ProcIDStr;
  308. CmdLine2 := '/C ' + ACompiler + ' ' + AOptions + ' > ' + TmpFileName;
  309. SysUtils.ExecuteProcess (GetEnvironmentVariable ('COMSPEC'), CmdLine2);
  310. Assign (TmpFile, TmpFileName);
  311. Reset (TmpFile, 1);
  312. BlockRead (TmpFile, Buf, BufSize, Count);
  313. Close (TmpFile);
  314. {$ELSE USE_SHELL}
  315. S:=TProcess.Create(Nil);
  316. S.Commandline:=ACompiler+' '+AOptions;
  317. S.ShowWindow:=swoHIDE;
  318. S.Options:=[poUsePipes];
  319. S.execute;
  320. Count:=s.output.read(buf,BufSize);
  321. S.Free;
  322. {$ENDIF USE_SHELL}
  323. SetLength(Result,Count);
  324. Move(Buf,Result[1],Count);
  325. end;
  326. Procedure GetCompilerInfo(const ACompiler, AOptions: string; out AVersion: string; out ACPU: TCpu; out aOS:TOS); overload;
  327. var
  328. infosl: TStringList;
  329. begin
  330. infosl:=TStringList.Create;
  331. try
  332. infosl.Delimiter:=' ';
  333. infosl.DelimitedText:=GetCompilerInfo(ACompiler,AOptions);
  334. if infosl.Count<>3 then
  335. Raise EPackagerError.Create(SErrInvalidFPCInfo);
  336. AVersion:=infosl[0];
  337. ACPU:=StringToCPU(infosl[1]);
  338. AOS:=StringToOS(infosl[2]);
  339. finally
  340. infosl.Free;
  341. end;
  342. end;
  343. function IsSuperUser:boolean;
  344. begin
  345. {$ifdef unix}
  346. result:=(fpGetUID=0);
  347. {$else unix}
  348. result:=false;
  349. {$endif unix}
  350. end;
  351. procedure ReadIniFile(Const AFileName: String;L:TStrings);
  352. Var
  353. F : TFileStream;
  354. Line : String;
  355. I,P,PC : Integer;
  356. begin
  357. F:=TFileStream.Create(AFileName,fmOpenRead);
  358. Try
  359. L.LoadFromStream(F);
  360. // Fix lines.
  361. For I:=L.Count-1 downto 0 do
  362. begin
  363. Line:=L[I];
  364. P:=Pos('=',Line);
  365. PC:=Pos(';',Line); // Comment line.
  366. If (P=0) or ((PC<>0) and (PC<P)) then
  367. L.Delete(I)
  368. else
  369. L[i]:=Trim(System.Copy(Line,1,P-1)+'='+Trim(System.Copy(Line,P+1,Length(Line)-P)));
  370. end;
  371. Finally
  372. F.Free;
  373. end;
  374. end;
  375. function GetFppkgConfigFile(Global : Boolean; SubDir : Boolean): string;
  376. var
  377. StoredOnGetApplicationName: TGetAppNameEvent;
  378. StoredOnGetVendorName: TGetVendorNameEvent;
  379. begin
  380. StoredOnGetApplicationName := OnGetApplicationName;
  381. StoredOnGetVendorName := OnGetVendorName;
  382. try
  383. OnGetApplicationName := @FPPkgGetApplicationName;
  384. OnGetVendorName := @FPPkgGetVendorName;
  385. result := GetAppConfigFile(Global, SubDir);
  386. finally
  387. OnGetApplicationName := StoredOnGetApplicationName;
  388. OnGetVendorName := StoredOnGetVendorName;
  389. end;
  390. end;
  391. function GetFppkgConfigDir(Global : Boolean): string;
  392. var
  393. StoredOnGetApplicationName: TGetAppNameEvent;
  394. StoredOnGetVendorName: TGetVendorNameEvent;
  395. begin
  396. StoredOnGetApplicationName := OnGetApplicationName;
  397. StoredOnGetVendorName := OnGetVendorName;
  398. try
  399. OnGetApplicationName := @FPPkgGetApplicationName;
  400. OnGetVendorName := @FPPkgGetVendorName;
  401. result := GetAppConfigDir(Global);
  402. finally
  403. OnGetApplicationName := StoredOnGetApplicationName;
  404. OnGetVendorName := StoredOnGetVendorName;
  405. end;
  406. end;
  407. initialization
  408. LogHandler := @LogCmd;
  409. ErrorHandler := @ErrorCmd;
  410. end.