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-2017 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 <kicad_curl/kicad_curl_easy.h> // Include before any wx file
74 #include <sstream>
75 #include <boost/ptr_container/ptr_map.hpp>
76 #include <set>
77 
78 #include <wx/zipstrm.h>
79 #include <wx/mstream.h>
80 #include <wx/uri.h>
81 
82 #include <fctsys.h>
83 
84 #include <io_mgr.h>
85 #include <richio.h>
86 #include <pcb_parser.h>
87 #include <class_board.h>
88 #include <github_plugin.h>
89 #include <class_module.h>
90 #include <macros.h>
91 #include <fp_lib_table.h> // ExpandSubstitutions()
92 #include <github_getliblist.h>
93 
94 
95 using namespace std;
96 
97 
98 static const char* PRETTY_DIR = "allow_pretty_writing_to_this_dir";
99 
100 
101 typedef boost::ptr_map< wxString, wxZipEntry > MODULE_MAP;
102 typedef MODULE_MAP::iterator MODULE_ITER;
103 typedef MODULE_MAP::const_iterator MODULE_CITER;
104 
105 
110 struct GH_CACHE : public MODULE_MAP
111 {
112  // MODULE_MAP is a boost::ptr_map template, made into a class hereby.
113 };
114 
115 
117  PCB_IO(),
118  m_gh_cache( 0 )
119 {
120 }
121 
122 
124 {
125  delete m_gh_cache;
126 }
127 
128 
129 const wxString GITHUB_PLUGIN::PluginName() const
130 {
131  return "Github";
132 }
133 
134 
135 const wxString GITHUB_PLUGIN::GetFileExtension() const
136 {
137  return wxEmptyString;
138 }
139 
140 
141 void GITHUB_PLUGIN::FootprintEnumerate( wxArrayString& aFootprintNames,
142  const wxString& aLibraryPath, const PROPERTIES* aProperties )
143 {
144  //D(printf("%s: this:%p aLibraryPath:'%s'\n", __func__, this, TO_UTF8(aLibraryPath) );)
145  cacheLib( aLibraryPath, aProperties );
146 
147  typedef std::set<wxString> MYSET;
148 
149  MYSET unique;
150 
151  if( m_pretty_dir.size() )
152  {
153  wxArrayString locals;
154 
156 
157  for( unsigned i=0; i<locals.GetCount(); ++i )
158  unique.insert( locals[i] );
159  }
160 
161  for( MODULE_ITER it = m_gh_cache->begin(); it!=m_gh_cache->end(); ++it )
162  {
163  unique.insert( it->first );
164  }
165 
166  for( MYSET::const_iterator it = unique.begin(); it != unique.end(); ++it )
167  {
168  aFootprintNames.Add( *it );
169  }
170 }
171 
172 
174  const wxString& aLibraryPath, const PROPERTIES* aProperties )
175 {
176  if( m_lib_path != aLibraryPath )
177  {
178  m_zip_image.clear();
179  }
180 
181  remoteGetZip( aLibraryPath );
182 }
183 
184 
185 MODULE* GITHUB_PLUGIN::FootprintLoad( const wxString& aLibraryPath,
186  const wxString& aFootprintName, const PROPERTIES* aProperties )
187 {
188  // D(printf("%s: this:%p aLibraryPath:'%s'\n", __func__, this, TO_UTF8(aLibraryPath) );)
189 
190  // clear or set to valid the variable m_pretty_dir
191  cacheLib( aLibraryPath, aProperties );
192 
193  if( m_pretty_dir.size() )
194  {
195  // API has FootprintLoad() *not* throwing an exception if footprint not found.
196  MODULE* local = PCB_IO::FootprintLoad( m_pretty_dir, aFootprintName, aProperties );
197 
198  if( local )
199  {
200  // It has worked, see <src>/scripts/test_kicad_plugin.py. So this was not firing:
201  // wxASSERT( aFootprintName == FROM_UTF8( local->GetFPID().GetLibItemName().c_str() ) );
202  // Moving it to higher API layer FP_LIB_TABLE::FootprintLoad().
203 
204  return local;
205  }
206  }
207 
208  MODULE_CITER it = m_gh_cache->find( aFootprintName );
209 
210  if( it != m_gh_cache->end() ) // fp_name is present
211  {
212  //std::string::data() ensures that the referenced data block is contiguous.
213  wxMemoryInputStream mis( m_zip_image.data(), m_zip_image.size() );
214 
215  // This decoder should always be UTF8, since it was saved that way by git.
216  // That is, since pretty footprints are UTF8, and they were pushed to the
217  // github repo, they are still UTF8.
218  wxZipInputStream zis( mis, wxConvUTF8 );
219  wxZipEntry* entry = (wxZipEntry*) it->second; // remove "const"-ness
220 
221  if( zis.OpenEntry( *entry ) )
222  {
223  INPUTSTREAM_LINE_READER reader( &zis, aLibraryPath );
224 
225  // I am a PCB_IO derivative with my own PCB_PARSER
226  m_parser->SetLineReader( &reader ); // ownership not passed
227 
228  MODULE* ret = (MODULE*) m_parser->Parse();
229 
230  // In a github library, (as well as in a "KiCad" library) the name of
231  // the pretty file defines the footprint name. That filename trumps
232  // any name found in the pretty file; any name in the pretty file
233  // must be ignored here. Also, the library nickname is unknown in
234  // this context so clear it just in case.
235  ret->SetFPID( aFootprintName );
236 
237  return ret;
238  }
239  }
240 
241  return NULL; // this API function returns NULL for "not found", per spec.
242 }
243 
244 
245 bool GITHUB_PLUGIN::IsFootprintLibWritable( const wxString& aLibraryPath )
246 {
247  if( m_pretty_dir.size() )
249  else
250  return false;
251 }
252 
253 
254 void GITHUB_PLUGIN::FootprintSave( const wxString& aLibraryPath,
255  const MODULE* aFootprint, const PROPERTIES* aProperties )
256 {
257  // set m_pretty_dir to either empty or something in aProperties
258  cacheLib( aLibraryPath, aProperties );
259 
260  if( GITHUB_PLUGIN::IsFootprintLibWritable( aLibraryPath ) )
261  {
262  PCB_IO::FootprintSave( m_pretty_dir, aFootprint, aProperties );
263  }
264  else
265  {
266  // This typically will not happen if the caller first properly calls
267  // IsFootprintLibWritable() to determine if calling FootprintSave() is
268  // even legal, so I spend no time on internationalization here:
269 
270  string msg = StrPrintf( "Github library\n'%s'\nis only writable if you set option '%s' in Library Tables dialog.",
271  TO_UTF8( aLibraryPath ), PRETTY_DIR );
272 
273  THROW_IO_ERROR( msg );
274  }
275 }
276 
277 
278 void GITHUB_PLUGIN::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName,
279  const PROPERTIES* aProperties )
280 {
281  // set m_pretty_dir to either empty or something in aProperties
282  cacheLib( aLibraryPath, aProperties );
283 
284  if( GITHUB_PLUGIN::IsFootprintLibWritable( aLibraryPath ) )
285  {
286  // Does the PCB_IO base class have this footprint?
287  // We cannot write to github.
288 
289  wxArrayString pretties;
290 
291  PCB_IO::FootprintEnumerate( pretties, m_pretty_dir, aProperties );
292 
293  if( pretties.Index( aFootprintName ) != wxNOT_FOUND )
294  {
295  PCB_IO::FootprintDelete( m_pretty_dir, aFootprintName, aProperties );
296  }
297  else
298  {
299  wxString msg = wxString::Format(
300  _( "Footprint\n'%s'\nis not in the writable portion of this Github library\n'%s'" ),
301  GetChars( aFootprintName ),
302  GetChars( aLibraryPath )
303  );
304 
305  THROW_IO_ERROR( msg );
306  }
307  }
308  else
309  {
310  // This typically will not happen if the caller first properly calls
311  // IsFootprintLibWritable() to determine if calling FootprintSave() is
312  // even legal, so I spend no time on internationalization here:
313 
314  string msg = StrPrintf( "Github library\n'%s'\nis only writable if you set option '%s' in Library Tables dialog.",
315  TO_UTF8( aLibraryPath ), PRETTY_DIR );
316 
317  THROW_IO_ERROR( msg );
318  }
319 }
320 
321 
322 void GITHUB_PLUGIN::FootprintLibCreate( const wxString& aLibraryPath, const PROPERTIES* aProperties )
323 {
324  // set m_pretty_dir to either empty or something in aProperties
325  cacheLib( aLibraryPath, aProperties );
326 
327  if( m_pretty_dir.size() )
328  {
330  }
331  else
332  {
333  // THROW_IO_ERROR() @todo
334  }
335 }
336 
337 
338 bool GITHUB_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties )
339 {
340  // set m_pretty_dir to either empty or something in aProperties
341  cacheLib( aLibraryPath, aProperties );
342 
343  if( m_pretty_dir.size() )
344  {
345  return PCB_IO::FootprintLibDelete( m_pretty_dir, aProperties );
346  }
347  else
348  {
349  // THROW_IO_ERROR() @todo
350  return false;
351  }
352 }
353 
354 
355 void GITHUB_PLUGIN::FootprintLibOptions( PROPERTIES* aListToAppendTo ) const
356 {
357  // inherit options supported by all PLUGINs.
358  PLUGIN::FootprintLibOptions( aListToAppendTo );
359 
360  (*aListToAppendTo)[ PRETTY_DIR ] = UTF8( _(
361  "Set this property to a directory where footprints are to be written as pretty "
362  "footprints when saving to this library. Anything saved will take precedence over "
363  "footprints by the same name in the github repo. These saved footprints can then "
364  "be sent to the library maintainer as updates. "
365  "<p>The directory <b>must</b> have a <b>.pretty</b> file extension because the "
366  "format of the save is pretty.</p>"
367  ));
368 
369  /*
370  (*aListToAppendTo)["cache_github_zip_in_this_dir"] = UTF8( _(
371  "Set this property to a directory where the github *.zip file will be cached. "
372  "This should speed up subsequent visits to this library."
373  ));
374  */
375 }
376 
377 
378 void GITHUB_PLUGIN::cacheLib( const wxString& aLibraryPath, const PROPERTIES* aProperties )
379 {
380  // This is edge triggered based on a change in 'aLibraryPath',
381  // usually it does nothing. When the edge fires, m_pretty_dir is set
382  // to either:
383  // 1) empty or
384  // 2) a verified and validated, writable, *.pretty directory.
385 
386  if( !m_gh_cache || m_lib_path != aLibraryPath )
387  {
388  delete m_gh_cache;
389  m_gh_cache = 0;
390  m_pretty_dir.clear();
391 
392  if( !m_lib_path.empty() )
393  {
394  // Library path wasn't empty before - it's been changed. Flush out the prefetch cache.
395  m_zip_image.clear();
396  }
397 
398  if( aProperties )
399  {
400  UTF8 pretty_dir;
401 
402  if( aProperties->Value( PRETTY_DIR, &pretty_dir ) )
403  {
404  wxString wx_pretty_dir = pretty_dir;
405 
406  wx_pretty_dir = LIB_TABLE::ExpandSubstitutions( wx_pretty_dir );
407 
408  wxFileName wx_pretty_fn = wx_pretty_dir;
409 
410  if( !wx_pretty_fn.IsOk() ||
411  !wx_pretty_fn.IsDirWritable() ||
412  wx_pretty_fn.GetExt() != "pretty"
413  )
414  {
415  wxString msg = wxString::Format(
416  _( "option '%s' for Github library '%s' must point to a writable directory ending with '.pretty'." ),
418  GetChars( aLibraryPath )
419  );
420 
421  THROW_IO_ERROR( msg );
422  }
423 
424  m_pretty_dir = wx_pretty_dir;
425  }
426  }
427 
428  // operator==( wxString, wxChar* ) does not exist, construct wxString once here.
429  const wxString kicad_mod( "kicad_mod" );
430 
431  //D(printf("%s: this:%p m_lib_path:'%s' aLibraryPath:'%s'\n", __func__, this, TO_UTF8( m_lib_path), TO_UTF8(aLibraryPath) );)
432  m_gh_cache = new GH_CACHE();
433 
434  // INIT_LOGGER( "/tmp", "test.log" );
435  remoteGetZip( aLibraryPath );
436  // UNINIT_LOGGER();
437 
438  m_lib_path = aLibraryPath;
439 
440  wxMemoryInputStream mis( &m_zip_image[0], m_zip_image.size() );
441 
442  // Recently the zip standard adopted UTF8 encoded filenames within the
443  // internal zip directory block. Please only use zip files that conform
444  // to that standard. Github seems to now, but may not have earlier.
445  wxZipInputStream zis( mis, wxConvUTF8 );
446 
447  wxZipEntry* entry;
448  wxString fp_name;
449 
450  while( ( entry = zis.GetNextEntry() ) != NULL )
451  {
452  wxFileName fn( entry->GetName() ); // chop long name into parts
453 
454  if( fn.GetExt() == kicad_mod )
455  {
456  fp_name = fn.GetName(); // omit extension & path
457 
458  m_gh_cache->insert( fp_name, entry );
459  }
460  else
461  delete entry;
462  }
463  }
464 }
465 
466 
467 bool GITHUB_PLUGIN::repoURL_zipURL( const wxString& aRepoURL, std::string* aZipURL )
468 {
469  // e.g. "https://github.com/liftoff-sr/pretty_footprints"
470  //D(printf("aRepoURL:%s\n", TO_UTF8( aRepoURL ) );)
471 
472  wxURI repo( aRepoURL );
473 
474  if( repo.HasServer() && repo.HasPath() )
475  {
476  // scheme might be "http" or if truly github.com then "https".
477  wxString zip_url;
478 
479  if( repo.GetServer() == "github.com" )
480  {
481  //codeload.github.com only supports https
482  zip_url = "https://";
483 #if 0 // A proper code path would be this one, but it is not the fastest.
484  zip_url += repo.GetServer();
485  zip_url += repo.GetPath(); // path comes with a leading '/'
486  zip_url += "/archive/master.zip";
487 #else
488  // Github issues a redirect for the "master.zip". i.e.
489  // "https://github.com/liftoff-sr/pretty_footprints/archive/master.zip"
490  // would be redirected to:
491  // "https://codeload.github.com/liftoff-sr/pretty_footprints/zip/master"
492 
493  // In order to bypass this redirect, saving time, we use the
494  // redirected URL on first attempt to save one HTTP GET hit.
495  zip_url += "codeload.github.com";
496  zip_url += repo.GetPath(); // path comes with a leading '/'
497  zip_url += "/zip/master";
498 #endif
499  }
500 
501  else
502  {
503  zip_url = repo.GetScheme();
504  zip_url += "://";
505 
506  // This is the generic code path for any server which can serve
507  // up zip files. The schemes tested include: http and https.
508 
509  // zip_url goal: "<scheme>://<server>[:<port>]/<path>"
510 
511  // Remember that <scheme>, <server>, <port> if present, and <path> all came
512  // from the lib_path in the fp-lib-table row.
513 
514  // This code path is used with the nginx proxy setup, but is useful
515  // beyond that.
516 
517  zip_url += repo.GetServer();
518 
519  if( repo.HasPort() )
520  {
521  zip_url += ':';
522  zip_url += repo.GetPort();
523  }
524 
525  zip_url += repo.GetPath(); // path comes with a leading '/'
526 
527  // Do not modify the path, we cannot anticipate the needs of all
528  // servers which are serving up zip files directly. URL modifications
529  // are more generally done in the server, rather than contaminating
530  // this code path with the needs of one particular inflexible server.
531  }
532 
533  *aZipURL = zip_url.utf8_str();
534  return true;
535  }
536  return false;
537 }
538 
539 
540 void GITHUB_PLUGIN::remoteGetZip( const wxString& aRepoURL )
541 {
542  std::string zip_url;
543 
544  if( !m_zip_image.empty() )
545  return;
546 
547  if( !repoURL_zipURL( aRepoURL, &zip_url ) )
548  {
549  wxString msg = wxString::Format( _( "Unable to parse URL:\n'%s'" ), GetChars( aRepoURL ) );
550  THROW_IO_ERROR( msg );
551  }
552 
553  wxLogDebug( wxT( "Attempting to download: " ) + zip_url );
554 
555  KICAD_CURL_EASY kcurl; // this can THROW_IO_ERROR
556 
557  kcurl.SetURL( zip_url.c_str() );
558  kcurl.SetUserAgent( "http://kicad-pcb.org" );
559  kcurl.SetHeader( "Accept", "application/zip" );
560  kcurl.SetFollowRedirects( true );
561 
562  try
563  {
564  kcurl.Perform();
565  m_zip_image = kcurl.GetBuffer();
566  }
567  catch( const IO_ERROR& ioe )
568  {
569  // https "GET" has failed, report this to API caller.
570  // Note: kcurl.Perform() does not return an error if the file to download is not found
571  static const char errorcmd[] = "http GET command failed"; // Do not translate this message
572 
573  UTF8 fmt( _( "%s\nCannot get/download Zip archive: '%s'\nfor library path: '%s'.\nReason: '%s'" ) );
574 
575  std::string msg = StrPrintf( fmt.c_str(),
576  errorcmd,
577  zip_url.c_str(),
578  TO_UTF8( aRepoURL ),
579  TO_UTF8( ioe.What() )
580  );
581 
582  THROW_IO_ERROR( msg );
583  }
584 
585  // If the zip archive is not existing, the received data is "Not Found" or "404: Not Found",
586  // and no error is returned by kcurl.Perform().
587  if( ( m_zip_image.compare( 0, 9, "Not Found", 9 ) == 0 ) ||
588  ( m_zip_image.compare( 0, 14, "404: Not Found", 14 ) == 0 ) )
589  {
590  UTF8 fmt( _( "Cannot download library '%s'.\nThe library does not exist on the server" ) );
591  std::string msg = StrPrintf( fmt.c_str(), TO_UTF8( aRepoURL ) );
592 
593  THROW_IO_ERROR( msg );
594  }
595 }
596 
597 #if 0 && defined(STANDALONE)
598 
599 int main( int argc, char** argv )
600 {
601  INIT_LOGGER( ".", "test.log" );
602 
603  GITHUB_PLUGIN gh;
604 
605  try
606  {
607  wxArrayString fps = gh.FootprintEnumerate(
608  "https://github.com/liftoff-sr/pretty_footprints",
609  NULL
610  );
611 
612  for( int i=0; i<(int)fps.Count(); ++i )
613  {
614  printf("[%d]:%s\n", i, TO_UTF8( fps[i] ) );
615  }
616  }
617  catch( const IO_ERROR& ioe )
618  {
619  printf( "%s\n", TO_UTF8(ioe.What()) );
620  }
621 
622  UNINIT_LOGGER();
623 
624  return 0;
625 }
626 
627 #endif
Class UTF8 is an 8 bit string that is assuredly encoded in UTF8, and supplies special conversion supp...
Definition: utf8.h:73
bool SetUserAgent(const std::string &aAgent)
Function SetUserAgent sets the request user agent.
MODULE_MAP::iterator MODULE_ITER
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...
Class PCB_IO is a PLUGIN derivation for saving and loading Pcbnew s-expression formatted files...
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:53
Class INPUTSTREAM_LINE_READER is a LINE_READER that reads from a wxInputStream object.
Definition: richio.h:290
static const wxString ExpandSubstitutions(const wxString &aString)
Function ExpandSubstitutions.
Class BOARD to handle a board.
bool Value(const char *aName, UTF8 *aFetchedValue=NULL) const
Function Value fetches a property by aName and returns true if that property was found, else false.
Definition: properties.cpp:24
MODULE_MAP::const_iterator MODULE_CITER
void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Return a list of footprint names contained within the library at aLibraryPath.
Class 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.
MODULE_MAP::iterator MODULE_ITER
Class PROPERTIES is a name/value tuple with unique names and optional values.
Definition: properties.h:34
void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Return a list of footprint names contained within the library at aLibraryPath.
void FootprintLibOptions(PROPERTIES *aListToAppendTo) const override
Function FootprintLibOptions appends supported PLUGIN options to aListToAppenTo along with internatio...
This file contains miscellaneous commonly used macros and functions.
std::string m_zip_image
byte image of the zip file in its entirety.
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:75
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
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...
int main(int argc, char **argv)
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...
std::map< std::string, MODULE * > MODULE_MAP
Definition: eagle_plugin.h:36
void cacheLib(const wxString &aLibraryPath, const PROPERTIES *aProperties)
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
PCB_PARSER * m_parser
BOARD_ITEM * Parse()
Definition: pcb_parser.cpp:405
LINE_READER * SetLineReader(LINE_READER *aReader)
Function SetLineReader sets aLineReader into the parser, and returns the previous one...
Definition: pcb_parser.h:296
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.
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
MODULE_MAP::const_iterator MODULE_CITER
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
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:205
void FootprintLibCreate(const wxString &aLibraryPath, const PROPERTIES *aProperties) override
Function FootprintLibCreate creates a new empty footprint library at aLibraryPath empty...
bool IsFootprintLibWritable(const wxString &aLibraryPath) override
Function IsFootprintLibWritable returns true iff the library at aLibraryPath is writable.
const char * c_str() const
Definition: utf8.h:107
void remoteGetZip(const wxString &aRepoURL)
Function remoteGetZip fetches a zip file image from a github repo synchronously.
Pcbnew s-expression file format parser definition.
Module description (excepted pads)
bool FootprintLibDelete(const wxString &aLibraryPath, const PROPERTIES *aProperties) override
Function FootprintLibDelete deletes an existing footprint library and returns true, or if library does not exist returns false, or throws an exception if library exists but is read only or cannot be deleted for some other reason.
bool FootprintLibDelete(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Function FootprintLibDelete deletes an existing footprint library and returns true, or if library does not exist returns false, or throws an exception if library exists but is read only or cannot be deleted for some other reason.
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.
virtual void FootprintLibOptions(PROPERTIES *aListToAppendTo) const
Function FootprintLibOptions appends supported PLUGIN options to aListToAppenTo along with internatio...
Definition: plugin.cpp:122
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:47
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
Class GH_CACHE assists only within GITHUB_PLUGIN and holds a map of footprint name to wxZipEntry...
void SetFPID(const LIB_ID &aFPID)
Definition: class_module.h:165
static const char * PRETTY_DIR
const wxString GetFileExtension() const override
Function GetFileExtension returns the file extension for the PLUGIN.