KiCad PCB EDA Suite
github_plugin.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
5  * Copyright (C) 2016-2020 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 
26 /*
27 Note:
28 If you are using this plugin without the supporting nginx caching server, then you
29 will never be happy with its performance. However, it is the fastest plugin in
30 existence when used with a local nginx and the nginx configuration file in this
31 directory. Nginx can be running in house on your network anywhere for this statement
32 to be true.
33 
34 Comments below pertain to use without nginx, so are not relevant in every case:
35 
36 While exploring the possibility of local caching of the zip file, I discovered
37 this command to retrieve the time stamp of the last commit into any particular
38 repo:
39 
40  $time curl -I -i https://api.github.com/repos/KiCad/Mounting_Holes.pretty/commits
41 
42 This gets just the header to what would otherwise return information on the repo
43 in JSON format, and is reasonably faster than actually getting the repo
44 in zip form. However it still takes 5 seconds or more when github is busy, so
45 I have lost my enthusiasm for local caching until a faster time stamp retrieval
46 mechanism can be found, or github gets more servers. But note that the occasionally
47 slow response is the exception rather than the norm. Normally the response is
48 down around a 1/3 of a second. The information we would use is in the header
49 named "Last-Modified" as seen below.
50 
51 HTTP/1.1 200 OK
52 Server: GitHub.com
53 Date: Mon, 27 Jan 2014 15:46:46 GMT
54 Content-Type: application/json; charset=utf-8
55 Status: 200 OK
56 X-RateLimit-Limit: 60
57 X-RateLimit-Remaining: 49
58 X-RateLimit-Reset: 1390839612
59 Cache-Control: public, max-age=60, s-maxage=60
60 Last-Modified: Mon, 02 Dec 2013 10:08:51 GMT
61 ETag: "3d04d760f469f2516a51a56eac63bbd5"
62 Vary: Accept
63 X-GitHub-Media-Type: github.beta
64 X-Content-Type-Options: nosniff
65 Content-Length: 6310
66 Access-Control-Allow-Credentials: true
67 Access-Control-Expose-Headers: ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval
68 Access-Control-Allow-Origin: *
69 X-GitHub-Request-Id: 411087C2:659E:50FD6E6:52E67F66
70 Vary: Accept-Encoding
71 */
72 
73 #include <boost/ptr_container/ptr_map.hpp>
74 #include <set>
75 
76 #include <kicad_curl/kicad_curl_easy.h> // Include before any wx file
77 
78 #include <wx/zipstrm.h>
79 #include <wx/mstream.h>
80 #include <wx/uri.h>
81 
82 #include <io_mgr.h>
83 #include <richio.h>
85 #include <class_board.h>
86 #include <github_plugin.h>
87 #include <class_module.h>
88 #include <fp_lib_table.h> // ExpandSubstitutions()
89 
90 
91 using namespace std;
92 
93 
94 static const char* PRETTY_DIR = "allow_pretty_writing_to_this_dir";
95 
96 
97 typedef boost::ptr_map< wxString, wxZipEntry > MODULE_MAP;
98 typedef MODULE_MAP::iterator MODULE_ITER;
99 typedef MODULE_MAP::const_iterator MODULE_CITER;
100 
101 
106 struct GH_CACHE : public MODULE_MAP
107 {
108  // MODULE_MAP is a boost::ptr_map template, made into a class hereby.
109 };
110 
111 
113  PCB_IO(),
114  m_gh_cache( 0 )
115 {
116 }
117 
118 
120 {
121  delete m_gh_cache;
122 }
123 
124 
125 const wxString GITHUB_PLUGIN::PluginName() const
126 {
127  return "Github";
128 }
129 
130 
131 const wxString GITHUB_PLUGIN::GetFileExtension() const
132 {
133  return wxEmptyString;
134 }
135 
136 
137 void GITHUB_PLUGIN::FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibPath,
138  bool aBestEfforts, const PROPERTIES* aProperties )
139 {
140  try
141  {
142  cacheLib( aLibPath, aProperties );
143 
144  typedef std::set<wxString> MYSET;
145 
146  MYSET unique;
147 
148  if( m_pretty_dir.size() )
149  {
150  wxArrayString locals;
151 
152  PCB_IO::FootprintEnumerate( locals, m_pretty_dir, aBestEfforts );
153 
154  for( unsigned i=0; i<locals.GetCount(); ++i )
155  unique.insert( locals[i] );
156  }
157 
158  for( MODULE_ITER it = m_gh_cache->begin(); it!=m_gh_cache->end(); ++it )
159  unique.insert( it->first );
160 
161  for( MYSET::const_iterator it = unique.begin(); it != unique.end(); ++it )
162  aFootprintNames.Add( *it );
163  }
164  catch( const IO_ERROR& ioe )
165  {
166  if( !aBestEfforts )
167  throw ioe;
168  }
169 }
170 
171 
173  const wxString& aLibraryPath, const PROPERTIES* aProperties )
174 {
175  if( m_lib_path != aLibraryPath )
176  {
177  m_zip_image.clear();
178  }
179 
180  remoteGetZip( aLibraryPath );
181 }
182 
183 
184 MODULE* GITHUB_PLUGIN::FootprintLoad( const wxString& aLibraryPath,
185  const wxString& aFootprintName, const PROPERTIES* aProperties )
186 {
187  // clear or set to valid the variable m_pretty_dir
188  cacheLib( aLibraryPath, aProperties );
189 
190  if( m_pretty_dir.size() )
191  {
192  // API has FootprintLoad() *not* throwing an exception if footprint not found.
193  MODULE* local = PCB_IO::FootprintLoad( m_pretty_dir, aFootprintName, aProperties );
194 
195  if( local )
196  {
197  // It has worked, see <src>/scripts/test_kicad_plugin.py. So this was not firing:
198  // wxASSERT( aFootprintName == FROM_UTF8( local->GetFPID().GetLibItemName().c_str() ) );
199  // Moving it to higher API layer FP_LIB_TABLE::FootprintLoad().
200 
201  return local;
202  }
203  }
204 
205  MODULE_CITER it = m_gh_cache->find( aFootprintName );
206 
207  if( it != m_gh_cache->end() ) // fp_name is present
208  {
209  //std::string::data() ensures that the referenced data block is contiguous.
210  wxMemoryInputStream mis( m_zip_image.data(), m_zip_image.size() );
211 
212  // This decoder should always be UTF8, since it was saved that way by git.
213  // That is, since pretty footprints are UTF8, and they were pushed to the
214  // github repo, they are still UTF8.
215  wxZipInputStream zis( mis, wxConvUTF8 );
216  wxZipEntry* entry = (wxZipEntry*) it->second; // remove "const"-ness
217 
218  if( zis.OpenEntry( *entry ) )
219  {
220  INPUTSTREAM_LINE_READER reader( &zis, aLibraryPath );
221 
222  // I am a PCB_IO derivative with my own PCB_PARSER
223  m_parser->SetLineReader( &reader ); // ownership not passed
224 
225  MODULE* ret = (MODULE*) m_parser->Parse();
226 
227  // In a github library, (as well as in a "KiCad" library) the name of
228  // the pretty file defines the footprint name. That filename trumps
229  // any name found in the pretty file; any name in the pretty file
230  // must be ignored here. Also, the library nickname is unknown in
231  // this context so clear it just in case.
232  ret->SetFPID( LIB_ID( wxEmptyString, aFootprintName ) );
233 
234  return ret;
235  }
236  }
237 
238  return NULL; // this API function returns NULL for "not found", per spec.
239 }
240 
241 
242 bool GITHUB_PLUGIN::IsFootprintLibWritable( const wxString& aLibraryPath )
243 {
244  if( m_pretty_dir.size() )
246  else
247  return false;
248 }
249 
250 
251 void GITHUB_PLUGIN::FootprintSave( const wxString& aLibraryPath,
252  const MODULE* aFootprint, const PROPERTIES* aProperties )
253 {
254  // set m_pretty_dir to either empty or something in aProperties
255  cacheLib( aLibraryPath, aProperties );
256 
257  if( GITHUB_PLUGIN::IsFootprintLibWritable( aLibraryPath ) )
258  {
259  PCB_IO::FootprintSave( m_pretty_dir, aFootprint, aProperties );
260  }
261  else
262  {
263  // This typically will not happen if the caller first properly calls
264  // IsFootprintLibWritable() to determine if calling FootprintSave() is
265  // even legal, so I spend no time on internationalization here:
266 
267  string msg = StrPrintf( "Github library\n\"%s\"\nis only writable if you set option \"%s\" in Library Tables dialog.",
268  TO_UTF8( aLibraryPath ), PRETTY_DIR );
269 
270  THROW_IO_ERROR( msg );
271  }
272 }
273 
274 
275 void GITHUB_PLUGIN::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName,
276  const PROPERTIES* aProperties )
277 {
278  // set m_pretty_dir to either empty or something in aProperties
279  cacheLib( aLibraryPath, aProperties );
280 
281  if( GITHUB_PLUGIN::IsFootprintLibWritable( aLibraryPath ) )
282  {
283  // Does the PCB_IO base class have this footprint?
284  // We cannot write to github.
285 
286  wxArrayString pretties;
287 
288  PCB_IO::FootprintEnumerate( pretties, m_pretty_dir, aProperties );
289 
290  if( pretties.Index( aFootprintName ) != wxNOT_FOUND )
291  {
292  PCB_IO::FootprintDelete( m_pretty_dir, aFootprintName, aProperties );
293  }
294  else
295  {
296  wxString msg = wxString::Format(
297  _( "Footprint\n\"%s\"\nis not in the writable portion of this Github library\n\"%s\"" ),
298  aFootprintName,
299  aLibraryPath
300  );
301 
302  THROW_IO_ERROR( msg );
303  }
304  }
305  else
306  {
307  // This typically will not happen if the caller first properly calls
308  // IsFootprintLibWritable() to determine if calling FootprintSave() is
309  // even legal, so I spend no time on internationalization here:
310 
311  string msg = StrPrintf( "Github library\n\"%s\"\nis only writable if you set option \"%s\" in Library Tables dialog.",
312  TO_UTF8( aLibraryPath ), PRETTY_DIR );
313 
314  THROW_IO_ERROR( msg );
315  }
316 }
317 
318 
319 void GITHUB_PLUGIN::FootprintLibCreate( const wxString& aLibraryPath, const PROPERTIES* aProperties )
320 {
321  // set m_pretty_dir to either empty or something in aProperties
322  cacheLib( aLibraryPath, aProperties );
323 
324  if( m_pretty_dir.size() )
326 }
327 
328 
329 bool GITHUB_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties )
330 {
331  // set m_pretty_dir to either empty or something in aProperties
332  cacheLib( aLibraryPath, aProperties );
333 
334  if( m_pretty_dir.size() )
335  return PCB_IO::FootprintLibDelete( m_pretty_dir, aProperties );
336 
337  return false;
338 }
339 
340 
341 void GITHUB_PLUGIN::FootprintLibOptions( PROPERTIES* aListToAppendTo ) const
342 {
343  // inherit options supported by all PLUGINs.
344  PLUGIN::FootprintLibOptions( aListToAppendTo );
345 
346  (*aListToAppendTo)[ PRETTY_DIR ] = UTF8( _(
347  "Set this property to a directory where footprints are to be written as pretty "
348  "footprints when saving to this library. Anything saved will take precedence over "
349  "footprints by the same name in the github repo. These saved footprints can then "
350  "be sent to the library maintainer as updates. "
351  "<p>The directory <b>must</b> have a <b>.pretty</b> file extension because the "
352  "format of the save is pretty.</p>"
353  ));
354 
355  /*
356  (*aListToAppendTo)["cache_github_zip_in_this_dir"] = UTF8( _(
357  "Set this property to a directory where the github *.zip file will be cached. "
358  "This should speed up subsequent visits to this library."
359  ));
360  */
361 }
362 
363 
364 void GITHUB_PLUGIN::cacheLib( const wxString& aLibraryPath, const PROPERTIES* aProperties )
365 {
366  // This is edge triggered based on a change in 'aLibraryPath',
367  // usually it does nothing. When the edge fires, m_pretty_dir is set
368  // to either:
369  // 1) empty or
370  // 2) a verified and validated, writable, *.pretty directory.
371 
372  if( !m_gh_cache || m_lib_path != aLibraryPath )
373  {
374  delete m_gh_cache;
375  m_gh_cache = 0;
376  m_pretty_dir.clear();
377 
378  if( !m_lib_path.empty() )
379  {
380  // Library path wasn't empty before - it's been changed. Flush out the prefetch cache.
381  m_zip_image.clear();
382  }
383 
384  if( aProperties )
385  {
386  UTF8 pretty_dir;
387 
388  if( aProperties->Value( PRETTY_DIR, &pretty_dir ) )
389  {
390  wxString wx_pretty_dir = pretty_dir;
391 
392  wx_pretty_dir = ExpandEnvVarSubstitutions( wx_pretty_dir, nullptr );
393 
394  wxFileName wx_pretty_fn = wx_pretty_dir;
395 
396  if( !wx_pretty_fn.IsOk() ||
397  !wx_pretty_fn.IsDirWritable() ||
398  wx_pretty_fn.GetExt() != "pretty"
399  )
400  {
401  wxString msg = wxString::Format(
402  _( "option \"%s\" for Github library \"%s\" must point to a writable directory ending with '.pretty'." ),
404  aLibraryPath
405  );
406 
407  THROW_IO_ERROR( msg );
408  }
409 
410  m_pretty_dir = wx_pretty_dir;
411  }
412  }
413 
414  // operator==( wxString, wxChar* ) does not exist, construct wxString once here.
415  const wxString kicad_mod( "kicad_mod" );
416 
417  m_gh_cache = new GH_CACHE();
418 
419  // INIT_LOGGER( "/tmp", "test.log" );
420  remoteGetZip( aLibraryPath );
421  // UNINIT_LOGGER();
422 
423  m_lib_path = aLibraryPath;
424 
425  wxMemoryInputStream mis( &m_zip_image[0], m_zip_image.size() );
426 
427  // Recently the zip standard adopted UTF8 encoded filenames within the
428  // internal zip directory block. Please only use zip files that conform
429  // to that standard. Github seems to now, but may not have earlier.
430  wxZipInputStream zis( mis, wxConvUTF8 );
431 
432  wxZipEntry* entry;
433  wxString fp_name;
434 
435  while( ( entry = zis.GetNextEntry() ) != NULL )
436  {
437  wxFileName fn( entry->GetName() ); // chop long name into parts
438 
439  if( fn.GetExt() == kicad_mod )
440  {
441  fp_name = fn.GetName(); // omit extension & path
442 
443  m_gh_cache->insert( fp_name, entry );
444  }
445  else
446  delete entry;
447  }
448  }
449 }
450 
451 
452 long long GITHUB_PLUGIN::GetLibraryTimestamp( const wxString& aLibraryPath ) const
453 {
454  // This plugin currently relies on the nginx server for caching (see comments
455  // at top of file).
456  // Since only the nginx server holds the timestamp information, we must defeat
457  // all caching above the nginx server.
458  return wxDateTime::Now().GetValue().GetValue();
459 
460 #if 0
461  // If we have no cache, return a number which won't match any stored timestamps
462  if( !m_gh_cache || m_lib_path != aLibraryPath )
463  return wxDateTime::Now().GetValue().GetValue();
464 
465  long long hash = m_gh_cache->GetTimestamp();
466 
467  if( m_pretty_dir.size() )
469 
470  return hash;
471 #endif
472 }
473 
474 
475 bool GITHUB_PLUGIN::repoURL_zipURL( const wxString& aRepoURL, std::string* aZipURL )
476 {
477  // e.g. "https://github.com/liftoff-sr/pretty_footprints"
478 
479  wxURI repo( aRepoURL );
480 
481  if( repo.HasServer() && repo.HasPath() )
482  {
483  // scheme might be "http" or if truly github.com then "https".
484  wxString zip_url;
485 
486  if( repo.GetServer() == "github.com" )
487  {
488  //codeload.github.com only supports https
489  zip_url = "https://";
490 #if 0 // A proper code path would be this one, but it is not the fastest.
491  zip_url += repo.GetServer();
492  zip_url += repo.GetPath(); // path comes with a leading '/'
493  zip_url += "/archive/master.zip";
494 #else
495  // Github issues a redirect for the "master.zip". i.e.
496  // "https://github.com/liftoff-sr/pretty_footprints/archive/master.zip"
497  // would be redirected to:
498  // "https://codeload.github.com/liftoff-sr/pretty_footprints/zip/master"
499 
500  // In order to bypass this redirect, saving time, we use the
501  // redirected URL on first attempt to save one HTTP GET hit.
502  zip_url += "codeload.github.com";
503  zip_url += repo.GetPath(); // path comes with a leading '/'
504  zip_url += "/zip/master";
505 #endif
506  }
507 
508  else
509  {
510  zip_url = repo.GetScheme();
511  zip_url += "://";
512 
513  // This is the generic code path for any server which can serve
514  // up zip files. The schemes tested include: http and https.
515 
516  // zip_url goal: "<scheme>://<server>[:<port>]/<path>"
517 
518  // Remember that <scheme>, <server>, <port> if present, and <path> all came
519  // from the lib_path in the fp-lib-table row.
520 
521  // This code path is used with the nginx proxy setup, but is useful
522  // beyond that.
523 
524  zip_url += repo.GetServer();
525 
526  if( repo.HasPort() )
527  {
528  zip_url += ':';
529  zip_url += repo.GetPort();
530  }
531 
532  zip_url += repo.GetPath(); // path comes with a leading '/'
533 
534  // Do not modify the path, we cannot anticipate the needs of all
535  // servers which are serving up zip files directly. URL modifications
536  // are more generally done in the server, rather than contaminating
537  // this code path with the needs of one particular inflexible server.
538  }
539 
540  *aZipURL = zip_url.utf8_str();
541  return true;
542  }
543  return false;
544 }
545 
546 
547 void GITHUB_PLUGIN::remoteGetZip( const wxString& aRepoURL )
548 {
549  std::string zip_url;
550 
551  if( !m_zip_image.empty() )
552  return;
553 
554  if( !repoURL_zipURL( aRepoURL, &zip_url ) )
555  {
556  wxString msg = wxString::Format( _( "Unable to parse URL:\n\"%s\"" ), aRepoURL );
557  THROW_IO_ERROR( msg );
558  }
559 
560  KICAD_CURL_EASY kcurl; // this can THROW_IO_ERROR
561 
562  kcurl.SetURL( zip_url.c_str() );
563  kcurl.SetUserAgent( "http://kicad-pcb.org" );
564  kcurl.SetHeader( "Accept", "application/zip" );
565  kcurl.SetFollowRedirects( true );
566 
567  try
568  {
569  kcurl.Perform();
570  m_zip_image = kcurl.GetBuffer();
571  }
572  catch( const IO_ERROR& ioe )
573  {
574  // https "GET" has failed, report this to API caller.
575  // Note: kcurl.Perform() does not return an error if the file to download is not found
576  static const char errorcmd[] = "http GET command failed"; // Do not translate this message
577 
578  UTF8 fmt( _( "%s\nCannot get/download Zip archive: \"%s\"\nfor library path: \"%s\".\nReason: \"%s\"" ) );
579 
580  std::string msg = StrPrintf( fmt.c_str(),
581  errorcmd,
582  zip_url.c_str(),
583  TO_UTF8( aRepoURL ),
584  TO_UTF8( ioe.What() )
585  );
586 
587  THROW_IO_ERROR( msg );
588  }
589 
590  // If the zip archive is not existing, the received data is "Not Found" or "404: Not Found",
591  // and no error is returned by kcurl.Perform().
592  if( ( m_zip_image.compare( 0, 9, "Not Found", 9 ) == 0 ) ||
593  ( m_zip_image.compare( 0, 14, "404: Not Found", 14 ) == 0 ) )
594  {
595  UTF8 fmt( _( "Cannot download library \"%s\".\nThe library does not exist on the server" ) );
596  std::string msg = StrPrintf( fmt.c_str(), TO_UTF8( aRepoURL ) );
597 
598  THROW_IO_ERROR( msg );
599  }
600 }
601 
602 #if 0 && defined(STANDALONE)
603 
604 int main( int argc, char** argv )
605 {
606  INIT_LOGGER( ".", "test.log" );
607 
608  GITHUB_PLUGIN gh;
609 
610  try
611  {
612  wxArrayString fps = gh.FootprintEnumerate(
613  "https://github.com/liftoff-sr/pretty_footprints",
614  NULL
615  );
616 
617  for( int i=0; i<(int)fps.Count(); ++i )
618  {
619  printf("[%d]:%s\n", i, TO_UTF8( fps[i] ) );
620  }
621  }
622  catch( const IO_ERROR& ioe )
623  {
624  printf( "%s\n", TO_UTF8(ioe.What()) );
625  }
626 
627  UNINIT_LOGGER();
628 
629  return 0;
630 }
631 
632 #endif
UTF8 is an 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to...
Definition: utf8.h:73
bool SetUserAgent(const std::string &aAgent)
Function SetUserAgent sets the request user agent.
const wxString PluginName() const override
Function PluginName returns a brief hard coded name for this PLUGIN.
void Perform()
Function perform equivalent to curl_easy_perform.
bool SetFollowRedirects(bool aFollow)
Function SetFollowRedirects enables the following of HTTP(s) and other redirects, by default curl doe...
PCB_IO is a PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aLibPath, bool aBestEfforts, const PROPERTIES *aProperties=NULL) override
Return a list of footprint names contained within the library at aLibraryPath.
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:109
main()
INPUTSTREAM_LINE_READER is a LINE_READER that reads from a wxInputStream object.
Definition: richio.h:291
MODULE_MAP::const_iterator MODULE_CITER
Template specialization to enable wxStrings for certain containers (e.g. unordered_map)
Definition: bitmap.cpp:58
KICAD_CURL_EASY wrapper interface around the curl_easy API.
bool IsFootprintLibWritable(const wxString &aLibraryPath) override
Function IsFootprintLibWritable returns true iff the library at aLibraryPath is writable.
virtual void FootprintLibOptions(PROPERTIES *aListToAppendTo) const
Function FootprintLibOptions appends supported PLUGIN options to aListToAppenTo along with internatio...
Definition: plugin.cpp:141
const wxString ExpandEnvVarSubstitutions(const wxString &aString, PROJECT *aProject)
Replace any environment variable & text variable references with their values.
Definition: common.cpp:255
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
MODULE_MAP::iterator MODULE_ITER
PROPERTIES is a name/value tuple with unique names and optional values.
Definition: properties.h:34
long long GetLibraryTimestamp(const wxString &aLibraryPath) const override
Generate a timestamp representing all the files in the library (including the library directory).
void FootprintLibOptions(PROPERTIES *aListToAppendTo) const override
Function FootprintLibOptions appends supported PLUGIN options to aListToAppenTo along with internatio...
std::map< wxString, MODULE * > MODULE_MAP
Definition: eagle_parser.h:51
std::string m_zip_image
byte image of the zip file in its entirety.
const char * c_str() const
Definition: utf8.h:107
int StrPrintf(std::string *result, const char *format,...)
Function StrPrintf is like sprintf() but the output is appended to a std::string instead of to a char...
Definition: richio.cpp:78
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:95
void FootprintSave(const wxString &aLibraryPath, const MODULE *aFootprint, const PROPERTIES *aProperties=NULL) override
Function FootprintSave will write aModule to an existing library located at aLibraryPath.
const std::string & GetBuffer()
Function GetBuffer returns a const reference to the recevied data buffer.
void FootprintLibCreate(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Function FootprintLibCreate creates a new empty footprint library at aLibraryPath empty.
#define NULL
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:29
void FootprintSave(const wxString &aLibraryPath, const MODULE *aFootprint, const PROPERTIES *aProperties=NULL) override
Function FootprintSave will write aModule to an existing library located at aLibraryPath.
wxString m_lib_path
from aLibraryPath, something like https://github.com/liftoff-sr/pretty_footprints
MODULE * FootprintLoad(const wxString &aLibraryPath, const wxString &aFootprintName, const PROPERTIES *aProperties=NULL) override
Function FootprintLoad loads a footprint having aFootprintName from the aLibraryPath containing a lib...
void cacheLib(const wxString &aLibraryPath, const PROPERTIES *aProperties)
long long GetLibraryTimestamp(const wxString &aLibraryPath) const override
Generate a timestamp representing all the files in the library (including the library directory).
Class GITHUB_PLUGIN implements a portion of pcbnew's PLUGIN interface to provide read only access to ...
boost::ptr_map< wxString, wxZipEntry > MODULE_MAP
wxString m_pretty_dir
BOARD_ITEM * Parse()
Definition: pcb_parser.cpp:485
LINE_READER * SetLineReader(LINE_READER *aReader)
Function SetLineReader sets aLineReader into the parser, and returns the previous one,...
Definition: pcb_parser.h:367
void FootprintDelete(const wxString &aLibraryPath, const wxString &aFootprintName, const PROPERTIES *aProperties=NULL) override
Function FootprintDelete deletes aFootprintName from the library at aLibraryPath.
bool SetURL(const std::string &aURL)
Function SetURL sets the request URL.
void FootprintDelete(const wxString &aLibraryPath, const wxString &aFootprintName, const PROPERTIES *aProperties=NULL) override
Function FootprintDelete deletes aFootprintName from the library at aLibraryPath.
void PrefetchLib(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Function PrefetchLib If possible, prefetches the specified library (e.g.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:201
void FootprintLibCreate(const wxString &aLibraryPath, const PROPERTIES *aProperties) override
Function FootprintLibCreate creates a new empty footprint library at aLibraryPath empty.
#define _(s)
Definition: 3d_actions.cpp:33
bool IsFootprintLibWritable(const wxString &aLibraryPath) override
Function IsFootprintLibWritable returns true iff the library at aLibraryPath is writable.
void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aLibraryPath, bool aBestEfforts, const PROPERTIES *aProperties=NULL) override
Return a list of footprint names contained within the library at aLibraryPath.
void remoteGetZip(const wxString &aRepoURL)
Function remoteGetZip fetches a zip file image from a github repo synchronously.
Pcbnew s-expression file format parser definition.
bool FootprintLibDelete(const wxString &aLibraryPath, const PROPERTIES *aProperties) override
Function FootprintLibDelete deletes an existing footprint library and returns true,...
bool FootprintLibDelete(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Function FootprintLibDelete deletes an existing footprint library and returns true,...
GH_CACHE * m_gh_cache
MODULE * FootprintLoad(const wxString &aLibraryPath, const wxString &aFootprintName, const PROPERTIES *aProperties) override
Function FootprintLoad loads a footprint having aFootprintName from the aLibraryPath containing a lib...
static bool repoURL_zipURL(const wxString &aRepoURL, std::string *aZipURL)
Function repoURL_zipURL translates a repo URL to a zipfile URL name as commonly seen on github....
void SetHeader(const std::string &aName, const std::string &aValue)
Function SetHeader sets an arbitrary header for the HTTP(s) request.
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
GH_CACHE assists only within GITHUB_PLUGIN and holds a map of footprint name to wxZipEntry.
bool Value(const char *aName, UTF8 *aFetchedValue=NULL) const
Function Value fetches a property by aName and returns true if that property was found,...
Definition: properties.cpp:24
void SetFPID(const LIB_ID &aFPID)
Definition: class_module.h:211
static const char * PRETTY_DIR
const wxString GetFileExtension() const override
Function GetFileExtension returns the file extension for the PLUGIN.