123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594 |
- {$mode objfpc}
- {$h+}
- { $DEFINE USESYNAPSE}
- {$IFDEF VER2_6}
- {$DEFINE USESYNAPSE}
- {$ENDIF}
- program googleapiconv;
- uses
- custapp, classes, sysutils, fpjson, jsonparser, fpwebclient,
- {$IFDEF USESYNAPSE}
- ssl_openssl,
- synapsewebclient,
- {$ELSE}
- fphttpwebclient,
- {$ENDIF}
- googlediscoverytopas, googleservice, restbase, pascodegen, restcodegen;
- Const
- BaseDiscoveryURL = 'https://www.googleapis.com/discovery/v1/apis/';
- Type
- { TGoogleAPIConverter }
- { TAPIEntry }
- TAPIEntry = Class(TCollectionItem)
- private
- FAPIIcon: String;
- FAPIName: String;
- FAPIUnitName: String;
- FFileName: String;
- Public
- Property APIName : String Read FAPIName Write FAPIName;
- Property FileName : String Read FFileName Write FFileName;
- Property APIUnitName : String Read FAPIUnitName Write FAPIUnitName;
- Property APIIcon : String Read FAPIIcon Write FAPIIcon;
- end;
- { TAPIEntries }
- TAPIEntries = Class(TCollection)
- private
- function GetE(AIndex : Integer): TAPIEntry;
- Public
- Function AddEntry : TAPIEntry;
- Property Entries [AIndex : Integer] : TAPIEntry Read GetE; default;
- end;
- TGoogleAPIConverter = CLass(TCustomApplication)
- private
- FDownloadOnly: Boolean;
- FKeepJSON: Boolean;
- FUnitPrefix: String;
- FVerbose: Boolean;
- procedure ConversionLog(Sender: TObject; LogType: TCodegenLogType; const Msg: String);
- procedure CreateFPMake(FileName: String; L: TAPIEntries);
- procedure DoAll(LocalFile, URL, OFN: String; AllVersions: Boolean);
- Procedure DoConversion(JS: TStream; AEntry : TAPIEntry) ;
- procedure DownloadIcon(APIEntry: TAPIentry);
- function GetList(LocalFile, URL: String; AllVersions: Boolean): TJSONObject;
- Function HttpGetJSON(Const URL : String; Response : TStream) : Boolean;
- procedure RegisterUnit(FileName: String; L: TAPIEntries);
- procedure Usage(Msg: String);
- Public
- Constructor Create(AOwner: TComponent); override;
- Destructor Destroy; override;
- Procedure DoRun; override;
- Property KeepJSON : Boolean Read FKeepJSON Write FKeepJSON;
- Property Verbose : Boolean Read FVerbose Write FVerbose;
- Property DownloadOnly : Boolean Read FDownloadOnly Write FDownloadOnly;
- Property UnitPrefix : String Read FUnitPrefix Write FUnitPrefix;
- end;
- { TAPIEntries }
- function TAPIEntries.GetE(AIndex : Integer): TAPIEntry;
- begin
- Result:=Items[AIndex] as TAPIEntry;
- end;
- function TAPIEntries.AddEntry: TAPIEntry;
- begin
- Result:=Add as TAPIEntry;
- end;
- Constructor TGoogleAPIConverter.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- StopOnException:=True;
- TDiscoveryJSONToPas.RegisterAllObjects;
- UnitPrefix:='google';
- end;
- Destructor TGoogleAPIConverter.Destroy;
- begin
- inherited Destroy;
- end;
- Function TGoogleAPIConverter.HttpGetJSON(Const URL: String; Response: TStream
- ): Boolean;
- Var
- Webclient : TAbstractWebClient;
- Req: TWebClientRequest;
- Resp : TWebClientResponse;
- begin
- Result:=True;
- Req:=Nil;
- Resp:=Nil;
- {$IFDEF USESYNAPSE}
- WebClient:=TSynapseWebClient.Create(Self);
- {$ELSE}
- WebClient:=TFPHTTPWebClient.Create(Self);
- {$ENDIF}
- try
- Req:=WebClient.CreateRequest;
- Req.ResponseContent:=Response;
- ConversionLog(Self,cltInfo,'Downloading: '+URL);
- Resp:=WebClient.ExecuteRequest('GET',URL,Req);
- Result:=(Resp<>Nil);
- finally
- Resp.Free;
- Req.Free;
- WebClient.Free;
- end;
- end;
- procedure TGoogleAPIConverter.Usage(Msg : String);
- begin
- If (Msg<>'') then
- Writeln('Error : ',Msg);
- Writeln('Usage : ',ExeName,' [options] [inputfile] [outputfile]');
- Writeln('Where options is one of: ');
- Writeln('-a --all Download and generate code for all preferred services.');
- Writeln('-A --All Download and generate code for all services.');
- Writeln('if one of these options is given, then:');
- Writeln(' a) The service name will be appended to the output filename.');
- Writeln(' b) The --input will be used as a json which lists the services.');
- Writeln('-b --baseclass=classname Class name to use as parent class for all classes.');
- Writeln('-b --baseclass=classname Class name to use as parent class for all classes.');
- Writeln('-m --fpmake=filename Generate fpmake program.');
- Writeln('-e --extraunits=units comma separated list of units to add to uses clause.');
- Writeln('-h --help this message');
- Writeln('-i --input=file input filename (overrides non-option inputfile)');
- Writeln('-I --icons Download service icon (size 16)');
- Writeln('-L --license=licensetext Set license text to be added to the top of the unit.');
- Writeln(' Use @filename to load license text from filename');
- Writeln('-o --output=file output filename (overrides non-option outputfile)');
- Writeln(' Default is to use input filename with extension .pp');
- Writeln('-p --classprefix=prefix Prefix to use in class names for all classes.');
- Writeln('-r --resourcesuffix=suffix Suffix to use for resource names. Default is Resource.');
- Writeln('-R --register=unit Register unit for Lazarus.');
- Writeln('-t --timestamp Add timestamp to generated unit.');
- Writeln('-u --url=URL URL to download the REST description from.');
- Writeln('-v --serviceversion=v Service version to download the REST description for.');
- Writeln('-V --verbose Write some diagnostic messages');
- Writeln('-k --keepjson Keep the downloaded JSON files');
- Writeln('-d --onlydownload Just download the files, do not actually convert.');
- Writeln(' Only effective if -k or --keepjson is also specified.');
- Writeln('-f --unitprefix Prefix for generated unit names. Default is "google"');
- Writeln('If the outputfilename is empty and cannot be determined, an error is returned');
- Halt(Ord(Msg<>''));
- end;
- function TGoogleAPIConverter.GetList(LocalFile, URL: String;
- AllVersions: Boolean): TJSONObject;
- Var
- D : TJSONData;
- S : TStream;
- begin
- if (LocalFile<>'') then
- S:=TFileStream.Create(LocalFile,fmOpenRead)
- else
- begin
- S:=TMemoryStream.Create;
- if (URL='') then
- URL:=BaseDiscoveryURL;
- If not AllVersions then
- URL:=URL+'?preferred=true';
- HTTPGetJSON(URL,S);
- S.Position:=0;
- end;
- try
- D:=GetJSON(S);
- if Not (D is TJSONObject) then
- begin
- D.Free;
- Raise Exception.CreateFmt('Source is not a valid JSON description',[LocalFile+URL]);
- end;
- Result:=D as TJSONObject;
- finally
- S.Free;
- end;
- end;
- procedure TGoogleAPIConverter.RegisterUnit(FileName :String; L : TAPIEntries);
- Var
- I : Integer;
- UN,N,V : String;
- begin
- UN:=ChangeFileext(ExtractFileName(FileName),'');
- With TStringList.Create do
- try
- Add(Format('unit %s;',[un]));
- Add('');
- Add('interface');
- Add('');
- Add('{$mode objfpc}{$h+}');
- Add('');
- Add('uses sysutils,classes;');
- Add('');
- Add('procedure register;');
- Add('');
- Add('implementation');
- Add('');
- Add('uses');
- if Hasoption('I','icon') then
- Add(' lazres,');
- Add(' restbase,');
- Add(' googleservice,');
- Add(' googlebase,');
- Add(' googleclient,');
- For I:=0 to L.Count-1 do
- begin
- N:=L[i].APIUnitName;
- if I<L.Count-1 then
- Add(' '+N+',')
- else
- Add(' '+N+';')
- end;
- Add('');
- Add('');
- Add('procedure register;');
- Add('');
- Add('begin');
- if Hasoption('I','icon') then
- Add('{$i '+un+'.inc}');
- Add(' RegisterComponents(''Google API'',[');
- Add(' TGoogleClient,');
- For I:=0 to L.Count-1 do
- begin
- N:=L[i].APIName;
- if I<L.Count-1 then
- Add(' '+N+',')
- else
- Add(' '+N)
- end;
- Add(' ]);');
- Add('end;');
- Add('');
- Add('end.');
- SaveToFile(FileName);
- finally
- Free;
- end;
- end;
- procedure TGoogleAPIConverter.ConversionLog(Sender: TObject;
- LogType: TCodegenLogType; const Msg: String);
- begin
- if Verbose then
- Writeln(StdErr,Msg);
- end;
- procedure TGoogleAPIConverter.CreateFPMake(FileName :String; L : TAPIEntries);
- Var
- I : Integer;
- UN,N,V : String;
- begin
- UN:=ChangeFileext(ExtractFileName(FileName),'');
- With TStringList.Create do
- try
- Add('program fpmake;');
- Add('');
- Add('{$mode objfpc}{$h+}');
- Add('');
- Add('uses sysutils,classes, fpmkunit;');
- Add('');
- Add('');
- Add('function StdDep(T : TTarget) : TTarget;');
- Add('begin');
- Add(' T.Dependencies.AddUnit(''googlebase'');');
- Add(' T.Dependencies.AddUnit(''googleservice'');');
- Add(' Result:=T;');
- Add('end;');
- Add('');
- Add('Procedure AddGoogle;');
- Add('');
- Add('Var');
- Add(' P : TPackage;');
- Add(' T : TTarget;');
- Add('');
- Add('begin');
- Add(' With Installer do');
- Add(' begin');
- Add(' P:=AddPackage(''googleapis'');');
- Add(' P.ShortName:=''googleap'';');
- Add(' T:=P.Targets.AddUnit(''googlebase.pp'');');
- Add(' T:=P.Targets.AddUnit(''googleclient.pp'');');
- Add(' T:=P.Targets.AddUnit(''googleservice.pp'');');
- Add(' T.Dependencies.AddUnit(''googleclient'');');
- Add(' T.Dependencies.AddUnit(''googlebase'');');
- For I:=0 to L.Count-1 do
- begin
- N:=L[i].APIUnitName;
- Add(Format(' T:=StdDep(P.Targets.AddUnit(''%s''));',[ExtractFileName(L[i].FAPIUnitName)]));
- end;
- Add(' end;');
- Add('end;');
- Add('');
- Add('{$ifndef ALLPACKAGES}');
- Add('begin');
- Add(' AddGoogle;');
- Add(' Installer.Run;');
- Add('end.');
- Add('{$endif ALLPACKAGES}');
- Add('');
- Add('procedure register;');
- Add('');
- Add('begin');
- SaveToFile(FileName);
- finally
- Free;
- end;
- end;
- procedure TGoogleAPIConverter.DoAll(LocalFile, URL, OFN : String; AllVersions : Boolean);
- Var
- D,O : TJSONObject;
- RS : TStringStream;
- A : TJSONArray;
- S : TJSONEnum;
- LFN,RU,E : String;
- UL : TAPIEntries;
- U : TAPIEntry;
- I : Integer;
- begin
- E:=ExtractFileExt(OFN);
- if (E='') then
- E:='.pp';
- UL:=Nil;
- D:=GetList(LocalFile,URL,ALlVersions);
- try
- UL:=TAPIEntries.Create(TAPIEntry);
- A:=D.Get('items',TJSONArray(Nil));
- For S in A do
- begin
- O:=S.Value as TJSONObject;
- if AllVersions or O.Get('preferred',false) then
- begin
- RU:=O.get('discoveryRestUrl');
- LFN:=UnitPrefix+O.get('name');
- if AllVersions then
- LFN:=LFN+'_'+StringReplace(O.get('version'),'.','',[rfReplaceAll]);
- if (OFN='') then
- LFN:=LFN+E
- else
- LFN:=ChangeFileExt(OFN,LFN+E);
- RS:=TStringStream.Create('');
- try
- if not HttpGetJSON(RU,RS) then
- Raise Exception.Create('Could not download rest description from URL: '+RU);
- ConversionLog(Self,cltInfo,Format('Converting service "%s" to unit: %s',[O.get('name'),LFN]));
- if KeepJSON then
- With TFIleStream.Create(ChangeFileExt(LFN,'.json'),fmCreate) do
- try
- CopyFrom(RS,0);
- finally
- Free;
- end;
- RS.Position:=0;
- U:=UL.AddEntry;
- U.FileName:=LFN;
- if not DownloadOnly then
- DoConversion(RS,U);
- finally
- RS.Free;
- end;
- end;
- end;
- if not DownloadOnly then
- begin
- if HasOption('R','register') then
- RegisterUnit(GetOptionValue('R','register'),UL);
- if HasOption('m','fpmake') then
- CreateFpMake(GetOptionValue('m','fpmake'),UL);
- end;
- if HasOption('I','icon') then
- For I:=0 to UL.Count-1 do
- DownloadIcon(UL[i]);
- finally
- UL.Free;
- D.Free;
- end;
- end;
- Procedure TGoogleAPIConverter.DoRun;
- Const
- MyO : Array[1..21] of ansistring
- = ('help','input:','output:','extraunits:','baseclass:','classprefix:',
- 'url:','service:','serviceversion:','resourcesuffix:','license:',
- 'All','all','register','icon','fpmake:','timestamp','verbose','keepjson',
- 'onlydownload','unitprefix');
- Var
- O,NonOpts : TStrings;
- URL, S, IFN, OFN : AnsiString;
- JS : TStream;
- DoAllServices : Boolean;
- APIEntry : TAPIEntry;
- begin
- JS:=Nil;
- O:=Nil;
- NonOpts:=TStringList.Create;
- try
- O:=TStringList.Create;
- For S in MyO do O.Add(S);
- S:=Checkoptions('hi:o:e:b:p:u:s:v:r:L:aAR:Im:tVkdf',O,TStrings(Nil),NonOpts,True);
- if NonOpts.Count>0 then
- IFN:=NonOpts[0];
- if NonOpts.Count>1 then
- OFN:=NonOpts[1];
- finally
- O.Free;
- NonOpts.Free;
- end;
- FVerbose:=HasOption('V','verbose');
- FKeepJSON:=HasOption('k','keepjson');
- if HasOption('f','unitprefix') then
- UnitPrefix:=GetOptionValue('f','unitprefix');
- If FKeepJSON Then
- FDownLoadOnly:=HasOption('d','onlydownload');
- if (S<>'') or HasOption('h','help') then
- Usage(S);
- DoAllServices:=HasOption('a','all') or HasOption('A','All');
- if HasOption('i','input') then
- IFN:=GetOptionValue('i','input');
- if HasOption('o','output') then
- OFN:=GetOptionValue('o','output');
- if HasOption('u','url') then
- URL:=GetOptionValue('u','url')
- else if hasOption('s','service') then
- begin
- URL:=BaseDiscoveryURL+getOptionValue('s','service');
- if (pos('/',getOptionValue('s','service'))= 0) and
- HasOption('v','serviceversion') then
- URL:=URL+getOptionValue('v','serviceversion');
- if (URL[Length(URL)]<>'/') then
- URL:=URL+'/';
- URL:=URL+'rest';
- end;
- if (not DoAllServices) and (IFN='') and (URL='') then
- Usage('Need an input filename or URL');
- if (OFN='') then
- if (IFN<>'') then
- OFN:=ChangeFileExt(IFN,'.pp')
- else if getOptionValue('s','service')<>'' then
- OFN:=UnitPrefix+getOptionValue('s','service')+'.pp';
- if (OFN='') and Not DoAllServices then
- Usage('Need an output filename');
- if DoAllServices then
- DoAll(IFN,URL,OFN,HasOption('A','All'))
- else
- begin
- APIEntry:=Nil;
- if (IFN='') and (URL<>'') then
- begin
- JS:=TMemoryStream.Create;
- if not HttpGetJSON(URL,JS) then
- Raise Exception.Create('Could not download from URL: '+URL);
- if KeepJSON then
- With TFIleStream.Create(ChangeFileExt(OFN,'.json'),fmCreate) do
- try
- CopyFrom(JS,0);
- finally
- Free;
- end;
- JS.POsition:=0;
- end
- else
- JS:=TFileStream.Create(IFN,fmOpenRead or fmShareDenyWrite);
- try
- if not DownLoadOnly then
- APIEntry:=TAPIEntry.Create(Nil);
- try
- APIEntry.FileName:=OFN;
- DoConversion(JS,APIEntry);
- if HasOption('I','icon') then
- DownloadIcon(APIEntry);
- finally
- APIEntry.Free;
- end;
- finally
- JS.Free;
- end;
- end;
- Terminate;
- end;
- procedure TGoogleAPIConverter.DownloadIcon(APIEntry : TAPIentry);
- Var
- FN : String;
- FS : TFileStream;
- begin
- if (APIEntry.APIIcon<>'') then
- begin
- FN:=ExtractFilePath(APIEntry.FileName)+APIEntry.APIName+ExtractFileExt(APIEntry.APIIcon);
- FS:=TFileStream.Create(FN,fmCreate);
- try
- if HasOption('V','verbose') then
- Writeln(Format('Downloading icon %s to %s',[APIEntry.APIIcon,FN]));
- HttpGetJSON(APIEntry.APIIcon,FS);
- finally
- FS.Free;
- end;
- end;
- end;
- Procedure TGoogleAPIConverter.DoConversion(JS: TStream; AEntry: TAPIEntry);
- Var
- L: String;
- O : TGoogleIcons;
- begin
- With TDiscoveryJSONToPas.Create(Nil) do
- try
- L:=GetOptionValue('L','license');
- if (L<>'') then
- begin
- if (L[1]<>'@') then
- LicenseText.Text:=L
- else
- begin
- Delete(L,1,1);
- LicenseText.LoadFromFile(L);
- end;
- end;
- OnLog:=@ConversionLog;
- ExtraUnits:=GetOptionValue('e','extraunits');
- if HasOption('b','baseclass') then
- BaseClassName:=GetOptionValue('b','baseclass');
- if HasOption('p','classprefix') then
- ClassPrefix:=GetOptionValue('p','classprefix');
- if HasOption('r','resourcesuffix') then
- ResourceSuffix:=GetOptionValue('r','resourcesuffix');
- AddTimeStamp:=HasOption('t','timestamp');
- LoadFromStream(JS);
- AEntry.APIUnitName:=ChangeFileExt(ExtractFileName(AEntry.FileName),'');
- AEntry.APIName:=APIClassName;
- O:=Description.icons;
- if Assigned(O) then
- AEntry.APIIcon:=O.x16;
- SaveToFile(AEntry.FileName);
- finally
- Free;
- end;
- end;
- Var
- Application : TGoogleAPIConverter;
- begin
- {$if declared(Heaptrc)}
- printleakedblock:=true;
- printfaultyblock:=true;
- add_tail:=true;
- SetHeapTraceOutput('heaptrc.txt');
- {$endif}
- Application:=TGoogleAPIConverter.Create(Nil);
- Application.Initialize;
- Application.Run;
- end.
|