fprepos.pp 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004
  1. {
  2. This file is part of the Free Pascal Utilities
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {$mode objfpc}
  11. {$H+}
  12. unit fprepos;
  13. interface
  14. uses
  15. classes,sysutils,
  16. contnrs,
  17. streamcoll;
  18. Const
  19. StreamVersion : Integer = 1;
  20. StreamSignature = $FEEF;
  21. Type
  22. // Keep syncronized with fpmkunit.pp
  23. TCpu=(cpuNone,
  24. i386,m68k,powerpc,sparc,x86_64,arm,powerpc64
  25. );
  26. TCPUS = Set of TCPU;
  27. // Keep syncronized with fpmkunit.pp
  28. TOS=(osNone,
  29. linux,go32v2,win32,os2,freebsd,beos,netbsd,
  30. amiga,atari, solaris, qnx, netware, openbsd,wdosx,
  31. palmos,macos,darwin,emx,watcom,morphos,netwlibc,
  32. win64,wince,gba,nds,embedded,symbian
  33. );
  34. TOSes = Set of TOS;
  35. { TFPVersion }
  36. TFPVersion = Class(TPersistent)
  37. private
  38. FMajor: Word;
  39. FMinor: Word;
  40. FRelease: Word;
  41. FSuffix: string;
  42. function GetAsString: String;
  43. function GetEmpty: Boolean;
  44. procedure SetAsString(const AValue: String);
  45. Public
  46. Procedure Assign(Source : TPersistent); override;
  47. Property AsString : String Read GetAsString Write SetAsString;
  48. Function CompareVersion(AVersion : TFPVersion) : Integer;
  49. Function SameVersion(AVersion : TFPVersion) : Boolean;
  50. Property Empty : Boolean Read GetEmpty;
  51. Published
  52. Property Release : Word Read FRelease Write FRelease;
  53. Property Major : Word Read FMajor Write FMajor;
  54. Property Minor : Word Read FMinor Write FMinor;
  55. Property Suffix : string Read FSuffix Write FSuffix;
  56. end;
  57. { TFPDependency }
  58. TFPDependency = Class(TStreamCollectionItem)
  59. private
  60. FMinVersion: TFPVersion;
  61. FPackageName: String;
  62. procedure SetMinVersion(const AValue: TFPVersion);
  63. Public
  64. Constructor Create(ACollection : TCollection); override;
  65. Destructor Destroy; override;
  66. Procedure LoadFromStream(Stream : TStream; Streamversion : Integer); override;
  67. Procedure SaveToStream(Stream : TStream); override;
  68. Procedure Assign(Source : TPersistent); override;
  69. Published
  70. Property PackageName : String Read FPackageName Write FPackageName;
  71. Property MinVersion : TFPVersion Read FMinVersion Write SetMinVersion;
  72. end;
  73. { TFPDepencencies }
  74. TFPDependencies = Class(TStreamCollection)
  75. private
  76. function GetDependency(Index : Integer): TFPDependency;
  77. procedure SetDependency(Index : Integer; const AValue: TFPDependency);
  78. public
  79. Function AddDependency(Const APackageName : String; AMinVersion : String = '') : TFPDependency;
  80. Property Dependencies[Index : Integer] : TFPDependency Read GetDependency Write SetDependency;default;
  81. end;
  82. { TFPPackage }
  83. TFPPackage = Class(TStreamCollectionItem)
  84. private
  85. FAuthor: String;
  86. FDescription: String;
  87. FEmail: String;
  88. FLicense: String;
  89. FName: String;
  90. FExternalURL: String;
  91. FFileName: String;
  92. FVersion: TFPVersion;
  93. FInstalledVersion: TFPVersion;
  94. FDependencies : TFPDependencies;
  95. FOSes : TOSES;
  96. FCPUs : TCPUS;
  97. function GetDependencies: TFPDependencies;
  98. function GetHasDependencies: Boolean;
  99. function GetFileName: String;
  100. procedure SetName(const AValue: String);
  101. procedure SetVersion(const AValue: TFPVersion);
  102. Protected
  103. Function CreateDependencies : TFPDependencies; virtual;
  104. Public
  105. Constructor Create(ACollection : TCollection); override;
  106. Destructor Destroy; override;
  107. Procedure LoadFromStream(Stream : TStream; Streamversion : Integer); override;
  108. Procedure SaveToStream(Stream : TStream); override;
  109. Procedure Assign(Source : TPersistent); override;
  110. Function AddDependency(Const APackageName : String; AMinVersion : String = '') : TFPDependency;
  111. Property HasDependencies : Boolean Read GetHasDependencies;
  112. Property Dependencies : TFPDependencies Read GetDependencies;
  113. Published
  114. Property Name : String Read FName Write SetName;
  115. Property Author : String Read FAuthor Write FAuthor;
  116. Property Version : TFPVersion Read FVersion Write SetVersion;
  117. Property InstalledVersion : TFPVersion Read FInstalledVersion Write FInstalledVersion;
  118. Property License : String Read FLicense Write FLicense;
  119. Property Description : String Read FDescription Write FDescription;
  120. Property ExternalURL : String Read FExternalURL Write FExternalURL;
  121. Property FileName : String Read GetFileName Write FFileName;
  122. Property Email : String Read FEmail Write FEmail;
  123. Property OSes : TOSes Read FOSes Write FOses;
  124. Property CPUs : TCPUs Read FCPUs Write FCPUs;
  125. end;
  126. { TFPPackages }
  127. TFPPackages = Class(TStreamCollection)
  128. private
  129. FVersion : Integer;
  130. function GetPackage(Index : Integer): TFPPackage;
  131. procedure SetPackage(Index : Integer; const AValue: TFPPackage);
  132. Protected
  133. Function CurrentStreamVersion : Integer; override;
  134. Public
  135. Function IndexOfPackage(PackageName : String) : Integer;
  136. Function FindPackage(PackageName : String) : TFPPackage;
  137. Function PackageByName(PackageName : String) : TFPPackage;
  138. Function AddPackage(PackageName : string) : TFPPackage;
  139. Property StreamVersion : Integer Read FVersion Write FVersion;
  140. Property Packages [Index : Integer] : TFPPackage Read GetPackage Write SetPackage; default;
  141. end;
  142. { TFPRepository }
  143. TFPRepository = Class(TComponent)
  144. Private
  145. FMaxDependencyLevel : Integer;
  146. FBackUpFiles: Boolean;
  147. FFileName: String;
  148. FPackages : TFPPackages;
  149. function GetPackage(Index : Integer): TFPPackage;
  150. function GetPackageCount: Integer;
  151. Protected
  152. procedure CreatePackages; virtual;
  153. Procedure BackupFile(AFileName : String); virtual;
  154. Procedure DoGetPackageDependencies(PackageName : String; List : TStringList; Level : Integer); virtual;
  155. Public
  156. Constructor Create(AOwner : TComponent); override;
  157. Destructor Destroy; override;
  158. // Loading and Saving repository. Own format.
  159. Procedure LoadFromStream(Stream : TStream); Virtual;
  160. Procedure SaveToStream(Stream : TStream); Virtual;
  161. Procedure LoadFromFile(AFileName : String);
  162. Procedure SaveToFile(AFileName : String);
  163. Procedure Save;
  164. // Loading and Saving version numbers: List of Name=Value pairs.
  165. Procedure LoadStatusFromStream(Stream : TStream); virtual;
  166. Procedure SaveStatusToStream(Stream : TStream); virtual;
  167. Procedure LoadStatusFromFile(AFileName : String);
  168. Procedure SaveStatusToFile(AFileName : String);
  169. // Package management
  170. Function IndexOfPackage(PackageName : String) : Integer;
  171. Function FindPackage(PackageName : String) : TFPPackage;
  172. Function PackageByName(PackageName : String) : TFPPackage;
  173. Procedure DeletePackage(Index : Integer);
  174. Procedure RemovePackage(PackageName : string);
  175. Function AddPackage(PackageName : string) : TFPPackage;
  176. // Dependencies
  177. Procedure GetPackageDependencies(PackageName : String; List : TObjectList; Recurse : Boolean);
  178. // Properties
  179. Property FileName : String Read FFileName;
  180. Property Packages[Index : Integer] : TFPPackage Read GetPackage; default;
  181. Property PackageCount : Integer Read GetPackageCount;
  182. Property BackupFiles : Boolean Read FBackUpFiles Write FBackupFiles;
  183. Property MaxDependencyLevel : Integer Read FMaxDependencyLevel Write FMaxDependencyLevel;
  184. Property PackageCollection : TFPPackages Read FPackages;
  185. end;
  186. EPackage = Class(Exception);
  187. Const
  188. // Max level of dependency searching before we decide it's a circular dependency.
  189. DefaultMaxDependencyLevel = 15;
  190. Function OSToString(OS: TOS) : String;
  191. Function OSesToString(OSes: TOSes) : String;
  192. Function CPUToString(CPU: TCPU) : String;
  193. Function CPUSToString(CPUS: TCPUS) : String;
  194. Function StringToOS(S : String) : TOS;
  195. Function OSesToString(S : String) : TOSes;
  196. Function StringToCPU(S : String) : TCPU;
  197. Function StringToCPUS(S : String) : TCPUS;
  198. Function MakeTargetString(CPU : TCPU;OS: TOS) : String;
  199. Procedure StringToCPUOS(S : String; Var CPU : TCPU; Var OS: TOS);
  200. Implementation
  201. uses
  202. typinfo,
  203. uriparser;
  204. ResourceString
  205. SErrInvalidCPU = 'Invalid CPU name : "%s"';
  206. SErrInvalidOS = 'Invalid OS name : "%s"';
  207. SErrInvalidMode = 'Invalid compiler mode : "%s"';
  208. SErrInvalidTarget = 'Invalid compiler target: %s';
  209. SErrPackageNotFound = 'Package "%s" not found.';
  210. SErrInvalidRepositorySig = 'Invalid repository stream. Stream signature incorrect';
  211. SErrBackupFailed = 'Failed to back up file "%s" to "%s".';
  212. SErrNoFileName = 'No filename for repository specified.';
  213. SErrDuplicatePackageName = 'Duplicate package name : "%s"';
  214. SErrMaxLevelExceeded = 'Maximum number of dependency levels exceeded (%d) at package "%s".';
  215. Function OSToString(OS: TOS) : String;
  216. begin
  217. Result:=LowerCase(GetenumName(TypeInfo(TOS),Ord(OS)));
  218. end;
  219. Function OSesToString(OSes: TOSes) : String;
  220. begin
  221. Result:=LowerCase(SetToString(PtypeInfo(TypeInfo(TOSes)),Integer(OSes),False));
  222. end;
  223. Function CPUToString(CPU: TCPU) : String;
  224. begin
  225. Result:=LowerCase(GetenumName(TypeInfo(TCPU),Ord(CPU)));
  226. end;
  227. Function CPUSToString(CPUS: TCPUS) : String;
  228. begin
  229. Result:=LowerCase(SetToString(PTypeInfo(TypeInfo(TCPUS)),Integer(CPUS),False));
  230. end;
  231. Function StringToOS(S : String) : TOS;
  232. Var
  233. I : Integer;
  234. begin
  235. I:=GetEnumValue(TypeInfo(TOS),S);
  236. if (I=-1) then
  237. Raise EPackage.CreateFmt(SErrInvalidOS,[S]);
  238. Result:=TOS(I);
  239. end;
  240. Function OSesToString(S : String) : TOSes;
  241. begin
  242. Result:=TOSes(StringToSet(PTypeInfo(TypeInfo(TOSes)),S));
  243. end;
  244. Function StringToCPU(S : String) : TCPU;
  245. Var
  246. I : Integer;
  247. begin
  248. I:=GetEnumValue(TypeInfo(TCPU),S);
  249. if (I=-1) then
  250. Raise EPackage.CreateFmt(SErrInvalidCPU,[S]);
  251. Result:=TCPU(I);
  252. end;
  253. Function StringToCPUS(S : String) : TCPUS;
  254. begin
  255. Result:=TCPUS(StringToSet(PTypeInfo(TypeInfo(TCPUS)),S));
  256. end;
  257. Function MakeTargetString(CPU : TCPU;OS: TOS) : String;
  258. begin
  259. Result:=CPUToString(CPU)+'-'+OSToString(OS);
  260. end;
  261. Procedure StringToCPUOS(S : String; Var CPU : TCPU; Var OS: TOS);
  262. Var
  263. P : integer;
  264. begin
  265. P:=Pos('-',S);
  266. If (P=0) then
  267. Raise EPackage.CreateFmt(SErrInvalidTarget,[S]);
  268. CPU:=StringToCPU(Copy(S,1,P-1));
  269. OS:=StringToOs(Copy(S,P+1,Length(S)-P));
  270. end;
  271. { TFPVersion }
  272. function TFPVersion.GetAsString: String;
  273. begin
  274. if Empty then
  275. Result:='<none>'
  276. else
  277. begin
  278. Result:=Format('%d.%d.%d',[Release,Major,Minor]);
  279. If (Suffix<>'') then
  280. Result:=Result+'-'+Suffix;
  281. end;
  282. end;
  283. function TFPVersion.GetEmpty: Boolean;
  284. begin
  285. Result:=(Release=0) and (Major=0) and (Minor=0) and (Suffix='');
  286. end;
  287. procedure TFPVersion.SetAsString(const AValue: String);
  288. Function NextDigit(sep : Char; var V : string) : integer;
  289. Var
  290. P : Integer;
  291. begin
  292. P:=Pos(Sep,V);
  293. If (P=0) then
  294. P:=Length(V)+1;
  295. Result:=StrToIntDef(Copy(V,1,P-1),-1);
  296. If Result<>-1 then
  297. Delete(V,1,P)
  298. else
  299. Result:=0;
  300. end;
  301. Var
  302. P : Integer;
  303. V : String;
  304. begin
  305. Release:=0;
  306. Major:=0;
  307. Minor:=0;
  308. Suffix:='';
  309. // Special support for empty version string
  310. if AValue='<none>' then
  311. exit;
  312. V:=AValue;
  313. Release:=NextDigit('.',V);
  314. Major:=NextDigit('.',V);
  315. Minor:=NextDigit('-',V);
  316. P:=Pos('-',V);
  317. If (P<>0) then
  318. Delete(V,1,P);
  319. Suffix:=V;
  320. end;
  321. procedure TFPVersion.Assign(Source: TPersistent);
  322. Var
  323. V : TFPVersion;
  324. begin
  325. if Source is TFPVersion then
  326. begin
  327. V:=Source as TFPVersion;
  328. Release:=V.Release;
  329. Major:=V.Major;
  330. Minor:=V.Minor;
  331. Suffix:=V.Suffix;
  332. end
  333. else
  334. inherited Assign(Source);
  335. end;
  336. function TFPVersion.CompareVersion(AVersion: TFPVersion): Integer;
  337. begin
  338. Result:=Release-AVersion.Release;
  339. If (Result=0) then
  340. begin
  341. Result:=Major-AVersion.Major;
  342. if (Result=0) then
  343. begin
  344. Result:=Minor-AVersion.Minor;
  345. If (Result=0) then
  346. Result:=CompareText(Suffix,AVersion.Suffix);
  347. end;
  348. end;
  349. end;
  350. function TFPVersion.SameVersion(AVersion: TFPVersion): Boolean;
  351. begin
  352. Result:=CompareVersion(AVersion)=0;
  353. end;
  354. { TFPPackage }
  355. procedure TFPPackage.SetVersion(const AValue: TFPVersion);
  356. begin
  357. if FVersion=AValue then
  358. exit;
  359. FVersion.Assign(AValue);
  360. end;
  361. Function TFPPackage.CreateDependencies : TFPDependencies;
  362. begin
  363. Result:=TFPDependencies.Create(TFPDependency);
  364. end;
  365. constructor TFPPackage.Create(ACollection: TCollection);
  366. begin
  367. inherited Create(ACollection);
  368. FVersion:=TFPVersion.Create;
  369. FInstalledVersion:=TFPVersion.Create;
  370. end;
  371. destructor TFPPackage.Destroy;
  372. begin
  373. FreeAndNil(FDependencies);
  374. FreeAndNil(FVersion);
  375. FreeAndNil(FInstalledVersion);
  376. inherited Destroy;
  377. end;
  378. procedure TFPPackage.SetName(const AValue: String);
  379. begin
  380. If (AValue<>FName) and (AValue<>'') then
  381. If (Collection<>Nil) and (Collection is TFPPackages) then
  382. // do not check while loading, this would slow down a lot !!
  383. if (not TFPPackages(Collection).Streaming) then
  384. If TFPPackages(Collection).IndexOfPackage(AValue)<>-1 then
  385. Raise EPackage.CreateFmt(SErrDuplicatePackageName,[AValue]);
  386. FName:=AValue;
  387. end;
  388. function TFPPackage.GetDependencies: TFPDependencies;
  389. begin
  390. If Not Assigned(FDependencies) then
  391. FDependencies:=CreateDependencies;
  392. Result:=FDependencies;
  393. end;
  394. function TFPPackage.GetHasDependencies: Boolean;
  395. begin
  396. Result:=(Dependencies<>nil) and (FDependencies.Count>0);
  397. end;
  398. function TFPPackage.GetFileName: String;
  399. var
  400. URI : TURI;
  401. begin
  402. if FFileName='' then
  403. begin
  404. URI:=ParseURI(ExternalURL);
  405. Result:=URI.Document;
  406. end
  407. else
  408. Result:=FFileName;
  409. end;
  410. procedure TFPPackage.LoadFromStream(Stream: TStream; Streamversion : Integer);
  411. Var
  412. B : Boolean;
  413. O : TOSes;
  414. C : TCPUs;
  415. I,J,Count : Integer;
  416. begin
  417. Version.AsString:=ReadString(Stream);
  418. Name:=ReadString(Stream);
  419. Author:=ReadString(Stream);
  420. License:=ReadString(Stream);
  421. Description:=ReadString(Stream);
  422. ExternalURL:=ReadString(Stream);
  423. FileName:=ReadString(Stream);
  424. Email:=ReadString(Stream);
  425. Count:=ReadInteger(Stream);
  426. O:=[];
  427. For I:=1 to Count do
  428. begin
  429. J:=GetEnumValue(TypeInfo(TOS),ReadString(Stream));
  430. If (J<>-1) then
  431. Include(O,TOS(J));
  432. end;
  433. OSEs:=O;
  434. Count:=ReadInteger(Stream);
  435. C:=[];
  436. For I:=1 to Count do
  437. begin
  438. J:=GetEnumValue(TypeInfo(TCPU),ReadString(Stream));
  439. If (J<>-1) then
  440. Include(C,TCPU(J));
  441. end;
  442. CPUS:=C;
  443. FreeAndNil(FDependencies);
  444. B:=ReadBoolean(Stream);
  445. If B then
  446. begin
  447. FDependencies:=CreateDependencies;
  448. FDependencies.LoadFromStream(Stream);
  449. end
  450. end;
  451. procedure TFPPackage.SaveToStream(Stream: TStream);
  452. Var
  453. Count : Integer;
  454. O : TOS;
  455. C : TCPU;
  456. begin
  457. WriteString(Stream,Version.AsString);
  458. WriteString(Stream,Name);
  459. WriteString(Stream,Author);
  460. WriteString(Stream,License);
  461. WriteString(Stream,Description);
  462. WriteString(Stream,ExternalURL);
  463. WriteString(Stream,FileName);
  464. WriteString(Stream,Email);
  465. { Write it like this, makes error checking easier when reading. }
  466. // OSes
  467. Count:=0;
  468. For O:=Low(TOS) to High(TOS) do
  469. If O in OSes then
  470. Inc(Count);
  471. WriteInteger(Stream,Count);
  472. For O:=Low(TOS) to High(TOS) do
  473. If O in OSes then
  474. WriteString(Stream,GetEnumName(TypeInfo(TOS),Ord(O)));
  475. // CPUs
  476. Count:=0;
  477. For C:=Low(TCPU) to High(TCPU) do
  478. If C in CPUS then
  479. Inc(Count);
  480. WriteInteger(Stream,Count);
  481. For C:=Low(TCPU) to High(TCPU) do
  482. If C in CPUS then
  483. WriteString(Stream,GetEnumName(TypeInfo(TCPU),Ord(C)));
  484. WriteBoolean(Stream,HasDependencies);
  485. If HasDependencies then
  486. FDependencies.SaveToStream(Stream);
  487. end;
  488. procedure TFPPackage.Assign(Source: TPersistent);
  489. Var
  490. P : TFPPackage;
  491. begin
  492. if Source is TFPPackage then
  493. begin
  494. P:=Source as TFPPackage;
  495. // This creates trouble if P has the same owning collection !!
  496. If P.Collection<>Collection then
  497. Name:=P.Name;
  498. Author:=P.Author;
  499. Version:=P.Version;
  500. Description:=P.Description;
  501. ExternalURL:=P.ExternalURL;
  502. FileName:=P.FileName;
  503. InstalledVersion:=P.Installedversion;
  504. If P.HasDependencies then
  505. Dependencies.Assign(P.Dependencies)
  506. else
  507. FreeAndNil(FDependencies);
  508. end
  509. else
  510. inherited Assign(Source);
  511. end;
  512. function TFPPackage.AddDependency(const APackageName: String;
  513. AMinVersion: String): TFPDependency;
  514. begin
  515. Result:=Dependencies.AddDependency(APackageName,AMinVersion);
  516. end;
  517. { TFPPackages }
  518. function TFPPackages.GetPackage(Index : Integer): TFPPackage;
  519. begin
  520. Result:=TFPPackage(Items[Index])
  521. end;
  522. procedure TFPPackages.SetPackage(Index : Integer; const AValue: TFPPackage);
  523. begin
  524. Items[Index]:=AValue;
  525. end;
  526. function TFPPackages.CurrentStreamVersion: Integer;
  527. begin
  528. Result:=FVersion;
  529. end;
  530. function TFPPackages.IndexOfPackage(PackageName: String): Integer;
  531. begin
  532. Result:=Count-1;
  533. While (Result>=0) and (CompareText(GetPackage(Result).Name,PackageName)<>0) do
  534. Dec(Result);
  535. end;
  536. function TFPPackages.FindPackage(PackageName: String): TFPPackage;
  537. Var
  538. I : Integer;
  539. begin
  540. I:=IndexOfPackage(PackageName);
  541. If (I=-1) then
  542. Result:=Nil
  543. else
  544. Result:=GetPackage(I);
  545. end;
  546. function TFPPackages.PackageByName(PackageName: String): TFPPackage;
  547. begin
  548. Result:=FindPackage(PackageName);
  549. If Result=Nil then
  550. Raise EPackage.CreateFmt(SErrPackageNotFound,[PackageName]);
  551. end;
  552. function TFPPackages.AddPackage(PackageName: string): TFPPackage;
  553. begin
  554. Result:=Add as TFPPackage;
  555. Try
  556. Result.Name:=PackageName;
  557. Except
  558. Result.Free;
  559. Raise;
  560. end;
  561. end;
  562. { TFPRepository }
  563. function TFPRepository.GetPackage(Index : Integer): TFPPackage;
  564. begin
  565. Result:=FPackages[Index];
  566. end;
  567. function TFPRepository.GetPackageCount: Integer;
  568. begin
  569. Result:=FPackages.Count;
  570. end;
  571. constructor TFPRepository.Create(AOwner: TComponent);
  572. begin
  573. inherited Create(AOwner);
  574. CreatePackages;
  575. FMaxDependencyLevel:=DefaultMaxDependencyLevel;
  576. end;
  577. procedure TFPRepository.CreatePackages;
  578. begin
  579. FPackages:=TFPPackages.Create(TFPPackage);
  580. FPackages.StreamVersion:=StreamVersion;
  581. end;
  582. procedure TFPRepository.BackupFile(AFileName: String);
  583. Var
  584. S : String;
  585. begin
  586. S:=AFileName+'.bak';
  587. if not RenameFile(AFileName,S) then
  588. Raise EPackage.CreateFmt(SErrBackupFailed,[AFileName,S]);
  589. end;
  590. destructor TFPRepository.Destroy;
  591. begin
  592. FreeAndNil(FPackages);
  593. inherited Destroy;
  594. end;
  595. procedure TFPRepository.LoadFromStream(Stream: TStream);
  596. Var
  597. I : Integer;
  598. V : Integer;
  599. begin
  600. Stream.ReadBuffer(I,SizeOf(Integer));
  601. If (I<>StreamSignature) then
  602. Raise EPackage.Create(SErrInvalidRepositorySig);
  603. Stream.ReadBuffer(V,SizeOf(V));
  604. FPackages.LoadFromStream(Stream);
  605. end;
  606. procedure TFPRepository.SaveToStream(Stream: TStream);
  607. Var
  608. i : Integer;
  609. begin
  610. I:=StreamSignature;
  611. Stream.WriteBuffer(I,SizeOf(Integer));
  612. I:=StreamVersion;
  613. Stream.WriteBuffer(I,SizeOf(Integer));
  614. FPackages.SaveToStream(Stream);
  615. end;
  616. procedure TFPRepository.LoadFromFile(AFileName: String);
  617. Var
  618. F : TFileStream;
  619. begin
  620. F:=TFileStream.Create(AFileName,fmopenRead);
  621. Try
  622. LoadFromStream(F);
  623. FFileName:=AFileName;
  624. Finally
  625. F.Free;
  626. end;
  627. end;
  628. procedure TFPRepository.SaveToFile(AFileName: String);
  629. Var
  630. F : TFileStream;
  631. begin
  632. If FileExists(AFileName) and BackupFiles then
  633. BackupFile(AFileName);
  634. F:=TFileStream.Create(AFileName,fmCreate);
  635. Try
  636. SaveToStream(F);
  637. FFileName:=AFileName;
  638. Finally
  639. F.Free;
  640. end;
  641. end;
  642. procedure TFPRepository.Save;
  643. begin
  644. If (FFileName='') then
  645. Raise EPackage.Create(SErrNoFileName);
  646. SaveToFile(FFileName);
  647. end;
  648. procedure TFPRepository.LoadStatusFromStream(Stream: TStream);
  649. Var
  650. L : TStrings;
  651. I : Integer;
  652. N,V : String;
  653. begin
  654. L:=TStringList.Create;
  655. Try
  656. L.LoadFromStream(Stream);
  657. For I:=0 to L.Count-1 do
  658. begin
  659. L.GetNameValue(I,N,V);
  660. If (N<>'') and (V<>'') then
  661. PackageByName(N).InstalledVersion.AsString:=V;
  662. end;
  663. Finally
  664. L.Free;
  665. end;
  666. end;
  667. procedure TFPRepository.SaveStatusToStream(Stream: TStream);
  668. Var
  669. L : TStrings;
  670. I : Integer;
  671. begin
  672. L:=TStringList.Create;
  673. Try
  674. For I:=0 to PackageCount-1 do
  675. With Packages[i] do
  676. if not InstalledVersion.Empty then
  677. L.Add(Name+'='+InstalledVersion.AsString);
  678. L.SaveToStream(Stream);
  679. Finally
  680. L.Free;
  681. end;
  682. end;
  683. procedure TFPRepository.LoadStatusFromFile(AFileName: String);
  684. Var
  685. F : TFileStream;
  686. begin
  687. F:=TFileStream.Create(AFileName,fmOpenRead);
  688. Try
  689. LoadStatusFromStream(F);
  690. Finally
  691. F.Free;
  692. end;
  693. end;
  694. procedure TFPRepository.SaveStatusToFile(AFileName: String);
  695. Var
  696. F : TFileStream;
  697. begin
  698. If FileExists(AFileName) and BackupFiles then
  699. BackupFile(AFileName);
  700. F:=TFileStream.Create(AFileName,fmCreate);
  701. Try
  702. SaveStatusToStream(F);
  703. Finally
  704. F.Free;
  705. end;
  706. end;
  707. function TFPRepository.IndexOfPackage(PackageName: String): Integer;
  708. begin
  709. Result:=FPackages.IndexOfPackage(PackageName);
  710. end;
  711. function TFPRepository.FindPackage(PackageName: String): TFPPackage;
  712. begin
  713. Result:=FPackages.FindPackage(PackageName);
  714. end;
  715. function TFPRepository.PackageByName(PackageName: String): TFPPackage;
  716. begin
  717. Result:=FPackages.PackageByName(PackageName);
  718. end;
  719. procedure TFPRepository.RemovePackage(PackageName: string);
  720. begin
  721. PackageByName(PackageName).Free;
  722. end;
  723. procedure TFPRepository.DeletePackage(Index : Integer);
  724. begin
  725. GetPackage(Index).Free;
  726. end;
  727. function TFPRepository.AddPackage(PackageName: string): TFPPackage;
  728. begin
  729. Result:=FPackages.AddPackage(PackageName);
  730. end;
  731. procedure TFPRepository.DoGetPackageDependencies(PackageName: String;
  732. List: TStringList; Level: Integer);
  733. Var
  734. P : TFPPackage;
  735. D2,D1 : TFPDependency;
  736. i,J : Integer;
  737. begin
  738. // If too many levels, bail out
  739. If (Level>FMaxDependencyLevel) then
  740. Raise EPackage.CreateFmt(SErrMaxLevelExceeded,[Level,PackageName]);
  741. // Check if it is a known package.
  742. P:=FindPackage(PackageName);
  743. If Assigned(P) and P.HasDependencies then
  744. For I:=0 to P.Dependencies.Count-1 do
  745. begin
  746. D1:=P.Dependencies[i];
  747. J:=List.IndexOf(PackageName);
  748. If J=-1 then
  749. begin
  750. // Dependency not yet in list.
  751. D2:=TFPDependency.Create(Nil);
  752. D2.Assign(D1);
  753. List.AddObject(D2.PackageName,D2);
  754. end
  755. else
  756. begin
  757. // Dependency already in list, compare versions.
  758. D2:=List.Objects[J] as TFPDependency;
  759. If D1.MinVersion.CompareVersion(D2.MinVersion)>0 then
  760. D2.MinVersion.Assign(D1.MinVersion);
  761. end;
  762. // If it was already in the list, we no longer recurse.
  763. If (Level>=0) and (J=-1) Then
  764. DoGetPackageDependencies(D2.PackageName,List,Level+1);
  765. end;
  766. end;
  767. procedure TFPRepository.GetPackageDependencies(PackageName: String;
  768. List: TObjectList; Recurse: Boolean);
  769. Var
  770. L : TStringList;
  771. I : Integer;
  772. begin
  773. L:=TStringList.Create;
  774. Try
  775. L.Sorted:=True;
  776. DoGetPackageDependencies(PackageName,L,Ord(Recurse)-1);
  777. For I:=0 to L.Count-1 do
  778. List.Add(L.Objects[i]);
  779. Finally
  780. // Freeing a stringlist does not free the objects.
  781. L.Free;
  782. end;
  783. end;
  784. { TFPDependency }
  785. procedure TFPDependency.SetMinVersion(const AValue: TFPVersion);
  786. begin
  787. FMinVersion.Assign(AValue);
  788. end;
  789. constructor TFPDependency.Create(ACollection: TCollection);
  790. begin
  791. inherited Create(ACollection);
  792. FMinVersion:=TFPVersion.Create;
  793. end;
  794. destructor TFPDependency.Destroy;
  795. begin
  796. FreeAndNil(FMinVersion);
  797. inherited Destroy;
  798. end;
  799. procedure TFPDependency.LoadFromStream(Stream: TStream; Streamversion: Integer
  800. );
  801. begin
  802. PackageName:=ReadString(Stream);
  803. MinVersion.AsString:=ReadString(Stream)
  804. end;
  805. procedure TFPDependency.SaveToStream(Stream: TStream);
  806. begin
  807. WriteString(Stream,PackageName);
  808. WriteString(Stream,MinVersion.AsString);
  809. end;
  810. procedure TFPDependency.Assign(Source: TPersistent);
  811. begin
  812. If Source is TFPDependency then
  813. With Source as TFPDependency do
  814. begin
  815. Self.PackageName:=PackageName;
  816. Self.MinVersion:=MinVersion;
  817. end
  818. else
  819. inherited Assign(Source);
  820. end;
  821. { TFPDependencies }
  822. function TFPDependencies.GetDependency(Index : Integer): TFPDependency;
  823. begin
  824. Result:=TFPDependency(Items[Index]);
  825. end;
  826. procedure TFPDependencies.SetDependency(Index : Integer;
  827. const AValue: TFPDependency);
  828. begin
  829. Items[Index]:=AValue;
  830. end;
  831. function TFPDependencies.AddDependency(const APackageName: String;
  832. AMinVersion: String): TFPDependency;
  833. begin
  834. Result:=Add as TFPDependency;
  835. Result.PackageName:=APackageName;
  836. If (AMinVersion<>'') then
  837. Result.MinVersion.AsString:=AMinVersion;
  838. end;
  839. end.