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 
28 While exploring the possibility of local caching of the zip file, I discovered
29 this command to retrieve the time stamp of the last commit into any particular
30 repo:
31 
32  $time curl -I -i https://api.github.com/repos/KiCad/Mounting_Holes.pretty/commits
33 
34 This gets just the header to what would otherwise return information on the repo
35 in JSON format, and is reasonably faster than actually getting the repo
36 in zip form. However it still takes 5 seconds or more when github is busy, so
37 I have lost my enthusiasm for local caching until a faster time stamp retrieval
38 mechanism can be found, or github gets more servers. But note that the occasionally
39 slow response is the exception rather than the norm. Normally the response is
40 down around a 1/3 of a second. The information we would use is in the header
41 named "Last-Modified" as seen below.
42 
43 
44 HTTP/1.1 200 OK
45 Server: GitHub.com
46 Date: Mon, 27 Jan 2014 15:46:46 GMT
47 Content-Type: application/json; charset=utf-8
48 Status: 200 OK
49 X-RateLimit-Limit: 60
50 X-RateLimit-Remaining: 49
51 X-RateLimit-Reset: 1390839612
52 Cache-Control: public, max-age=60, s-maxage=60
53 Last-Modified: Mon, 02 Dec 2013 10:08:51 GMT
54 ETag: "3d04d760f469f2516a51a56eac63bbd5"
55 Vary: Accept
56 X-GitHub-Media-Type: github.beta
57 X-Content-Type-Options: nosniff
58 Content-Length: 6310
59 Access-Control-Allow-Credentials: true
60 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
61 Access-Control-Allow-Origin: *
62 X-GitHub-Request-Id: 411087C2:659E:50FD6E6:52E67F66
63 Vary: Accept-Encoding
64 */
65 
66 #include <kicad_curl/kicad_curl_easy.h> // Include before any wx file
67 #include <sstream>
68 #include <boost/ptr_container/ptr_map.hpp>
69 #include <set>
70 
71 #include <wx/zipstrm.h>
72 #include <wx/mstream.h>
73 #include <wx/uri.h>
74 
75 #include <fctsys.h>
76 
77 #include <io_mgr.h>
78 #include <richio.h>
79 #include <pcb_parser.h>
80 #include <class_board.h>
81 #include <github_plugin.h>
82 #include <class_module.h>
83 #include <macros.h>
84 #include <fp_lib_table.h> // ExpandSubstitutions()
85 #include <github_getliblist.h>
86 
87 
88 using namespace std;
89 
90 
91 static const char* PRETTY_DIR = "allow_pretty_writing_to_this_dir";
92 
93 
94 typedef boost::ptr_map<string, wxZipEntry> MODULE_MAP;
95 typedef MODULE_MAP::iterator MODULE_ITER;
96 typedef MODULE_MAP::const_iterator MODULE_CITER;
97 
98 
103 struct GH_CACHE : public MODULE_MAP
104 {
105  // MODULE_MAP is a boost::ptr_map template, made into a class hereby.
106 };
107 
108 
110  PCB_IO(),
111  m_gh_cache( 0 )
112 {
113 }
114 
115 
117 {
118  delete m_gh_cache;
119 }
120 
121 
122 const wxString GITHUB_PLUGIN::PluginName() const
123 {
124  return "Github";
125 }
126 
127 
128 const wxString GITHUB_PLUGIN::GetFileExtension() const
129 {
130  return wxEmptyString;
131 }
132 
133 
135  const wxString& aLibraryPath, const PROPERTIES* aProperties )
136 {
137  //D(printf("%s: this:%p aLibraryPath:'%s'\n", __func__, this, TO_UTF8(aLibraryPath) );)
138  cacheLib( aLibraryPath, aProperties );
139 
140  typedef std::set<wxString> MYSET;
141 
142  MYSET unique;
143 
144  if( m_pretty_dir.size() )
145  {
146  wxArrayString locals = PCB_IO::FootprintEnumerate( m_pretty_dir );
147 
148  for( unsigned i=0; i<locals.GetCount(); ++i )
149  unique.insert( locals[i] );
150  }
151 
152  for( MODULE_ITER it = m_gh_cache->begin(); it!=m_gh_cache->end(); ++it )
153  {
154  unique.insert( FROM_UTF8( it->first.c_str() ) );
155  }
156 
157  wxArrayString ret;
158 
159  for( MYSET::const_iterator it = unique.begin(); it != unique.end(); ++it )
160  {
161  ret.Add( *it );
162  }
163 
164  return ret;
165 }
166 
167 
169  const wxString& aLibraryPath, const PROPERTIES* aProperties )
170 {
171  if( m_lib_path != aLibraryPath )
172  {
173  m_zip_image.clear();
174  }
175 
176  remoteGetZip( aLibraryPath );
177 }
178 
179 
180 MODULE* GITHUB_PLUGIN::FootprintLoad( const wxString& aLibraryPath,
181  const wxString& aFootprintName, const PROPERTIES* aProperties )
182 {
183  // D(printf("%s: this:%p aLibraryPath:'%s'\n", __func__, this, TO_UTF8(aLibraryPath) );)
184 
185  // clear or set to valid the variable m_pretty_dir
186  cacheLib( aLibraryPath, aProperties );
187 
188  if( m_pretty_dir.size() )
189  {
190  // API has FootprintLoad() *not* throwing an exception if footprint not found.
191  MODULE* local = PCB_IO::FootprintLoad( m_pretty_dir, aFootprintName, aProperties );
192 
193  if( local )
194  {
195  // It has worked, see <src>/scripts/test_kicad_plugin.py. So this was not firing:
196  // wxASSERT( aFootprintName == FROM_UTF8( local->GetFPID().GetLibItemName().c_str() ) );
197  // Moving it to higher API layer FP_LIB_TABLE::FootprintLoad().
198 
199  return local;
200  }
201  }
202 
203  UTF8 fp_name = aFootprintName;
204 
205  MODULE_CITER it = m_gh_cache->find( fp_name );
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( fp_name );
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 = PCB_IO::FootprintEnumerate( m_pretty_dir, aProperties );
287 
288  if( pretties.Index( aFootprintName ) != wxNOT_FOUND )
289  {
290  PCB_IO::FootprintDelete( m_pretty_dir, aFootprintName, aProperties );
291  }
292  else
293  {
294  wxString msg = wxString::Format(
295  _( "Footprint\n'%s'\nis not in the writable portion of this Github library\n'%s'" ),
296  GetChars( aFootprintName ),
297  GetChars( aLibraryPath )
298  );
299 
300  THROW_IO_ERROR( msg );
301  }
302  }
303  else
304  {
305  // This typically will not happen if the caller first properly calls
306  // IsFootprintLibWritable() to determine if calling FootprintSave() is
307  // even legal, so I spend no time on internationalization here:
308 
309  string msg = StrPrintf( "Github library\n'%s'\nis only writable if you set option '%s' in Library Tables dialog.",
310  TO_UTF8( aLibraryPath ), PRETTY_DIR );
311 
312  THROW_IO_ERROR( msg );
313  }
314 }
315 
316 
317 void GITHUB_PLUGIN::FootprintLibCreate( const wxString& aLibraryPath, const PROPERTIES* aProperties )
318 {
319  // set m_pretty_dir to either empty or something in aProperties
320  cacheLib( aLibraryPath, aProperties );
321 
322  if( m_pretty_dir.size() )
323  {
325  }
326  else
327  {
328  // THROW_IO_ERROR() @todo
329  }
330 }
331 
332 
333 bool GITHUB_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties )
334 {
335  // set m_pretty_dir to either empty or something in aProperties
336  cacheLib( aLibraryPath, aProperties );
337 
338  if( m_pretty_dir.size() )
339  {
340  return PCB_IO::FootprintLibDelete( m_pretty_dir, aProperties );
341  }
342  else
343  {
344  // THROW_IO_ERROR() @todo
345  return false;
346  }
347 }
348 
349 
350 void GITHUB_PLUGIN::FootprintLibOptions( PROPERTIES* aListToAppendTo ) const
351 {
352  // inherit options supported by all PLUGINs.
353  PLUGIN::FootprintLibOptions( aListToAppendTo );
354 
355  (*aListToAppendTo)[ PRETTY_DIR ] = UTF8( _(
356  "Set this property to a directory where footprints are to be written as pretty "
357  "footprints when saving to this library. Anything saved will take precedence over "
358  "footprints by the same name in the github repo. These saved footprints can then "
359  "be sent to the library maintainer as updates. "
360  "<p>The directory <b>must</b> have a <b>.pretty</b> file extension because the "
361  "format of the save is pretty.</p>"
362  ));
363 
364  /*
365  (*aListToAppendTo)["cache_github_zip_in_this_dir"] = UTF8( _(
366  "Set this property to a directory where the github *.zip file will be cached. "
367  "This should speed up subsequent visits to this library."
368  ));
369  */
370 }
371 
372 
373 void GITHUB_PLUGIN::cacheLib( const wxString& aLibraryPath, const PROPERTIES* aProperties )
374 {
375  // This is edge triggered based on a change in 'aLibraryPath',
376  // usually it does nothing. When the edge fires, m_pretty_dir is set
377  // to either:
378  // 1) empty or
379  // 2) a verified and validated, writable, *.pretty directory.
380 
381  if( !m_gh_cache || m_lib_path != aLibraryPath )
382  {
383  delete m_gh_cache;
384  m_gh_cache = 0;
385  m_pretty_dir.clear();
386 
387  if( !m_lib_path.empty() )
388  {
389  // Library path wasn't empty before - it's been changed. Flush out the prefetch cache.
390  m_zip_image.clear();
391  }
392 
393  if( aProperties )
394  {
395  UTF8 pretty_dir;
396 
397  if( aProperties->Value( PRETTY_DIR, &pretty_dir ) )
398  {
399  wxString wx_pretty_dir = pretty_dir;
400 
401  wx_pretty_dir = LIB_TABLE::ExpandSubstitutions( wx_pretty_dir );
402 
403  wxFileName wx_pretty_fn = wx_pretty_dir;
404 
405  if( !wx_pretty_fn.IsOk() ||
406  !wx_pretty_fn.IsDirWritable() ||
407  wx_pretty_fn.GetExt() != "pretty"
408  )
409  {
410  wxString msg = wxString::Format(
411  _( "option '%s' for Github library '%s' must point to a writable directory ending with '.pretty'." ),
413  GetChars( aLibraryPath )
414  );
415 
416  THROW_IO_ERROR( msg );
417  }
418 
419  m_pretty_dir = wx_pretty_dir;
420  }
421  }
422 
423  // operator==( wxString, wxChar* ) does not exist, construct wxString once here.
424  const wxString kicad_mod( "kicad_mod" );
425 
426  //D(printf("%s: this:%p m_lib_path:'%s' aLibraryPath:'%s'\n", __func__, this, TO_UTF8( m_lib_path), TO_UTF8(aLibraryPath) );)
427  m_gh_cache = new GH_CACHE();
428 
429  // INIT_LOGGER( "/tmp", "test.log" );
430  remoteGetZip( aLibraryPath );
431  // UNINIT_LOGGER();
432 
433  m_lib_path = aLibraryPath;
434 
435  wxMemoryInputStream mis( &m_zip_image[0], m_zip_image.size() );
436 
437  // @todo: generalize this name encoding from a PROPERTY (option) later
438  wxZipInputStream zis( mis, wxConvUTF8 );
439 
440  wxZipEntry* entry;
441 
442  while( ( entry = zis.GetNextEntry() ) != NULL )
443  {
444  wxFileName fn( entry->GetName() ); // chop long name into parts
445 
446  if( fn.GetExt() == kicad_mod )
447  {
448  UTF8 fp_name = fn.GetName(); // omit extension & path
449 
450  m_gh_cache->insert( fp_name, entry );
451  }
452  else
453  delete entry;
454  }
455  }
456 }
457 
458 
459 bool GITHUB_PLUGIN::repoURL_zipURL( const wxString& aRepoURL, std::string* aZipURL )
460 {
461  // e.g. "https://github.com/liftoff-sr/pretty_footprints"
462  //D(printf("aRepoURL:%s\n", TO_UTF8( aRepoURL ) );)
463 
464  wxURI repo( aRepoURL );
465 
466  if( repo.HasServer() && repo.HasPath() )
467  {
468  // scheme might be "http" or if truly github.com then "https".
469  wxString zip_url;
470 
471  if( repo.GetServer() == "github.com" )
472  {
473  //codeload.github.com only supports https
474  zip_url = "https://";
475 #if 0 // A proper code path would be this one, but it is not the fastest.
476  zip_url += repo.GetServer();
477  zip_url += repo.GetPath(); // path comes with a leading '/'
478  zip_url += "/archive/master.zip";
479 #else
480  // Github issues a redirect for the "master.zip". i.e.
481  // "https://github.com/liftoff-sr/pretty_footprints/archive/master.zip"
482  // would be redirected to:
483  // "https://codeload.github.com/liftoff-sr/pretty_footprints/zip/master"
484 
485  // In order to bypass this redirect, saving time, we use the
486  // redirected URL on first attempt to save one HTTP GET hit.
487  zip_url += "codeload.github.com";
488  zip_url += repo.GetPath(); // path comes with a leading '/'
489  zip_url += "/zip/master";
490 #endif
491  }
492 
493  else
494  {
495  zip_url = repo.GetScheme();
496  zip_url += "://";
497 
498  // This is the generic code path for any server which can serve
499  // up zip files. The schemes tested include: http and https.
500 
501  // zip_url goal: "<scheme>://<server>[:<port>]/<path>"
502 
503  // Remember that <scheme>, <server>, <port> if present, and <path> all came
504  // from the lib_path in the fp-lib-table row.
505 
506  // This code path is used with the nginx proxy setup, but is useful
507  // beyond that.
508 
509  zip_url += repo.GetServer();
510 
511  if( repo.HasPort() )
512  {
513  zip_url += ':';
514  zip_url += repo.GetPort();
515  }
516 
517  zip_url += repo.GetPath(); // path comes with a leading '/'
518 
519  // Do not modify the path, we cannot anticipate the needs of all
520  // servers which are serving up zip files directly. URL modifications
521  // are more generally done in the server, rather than contaminating
522  // this code path with the needs of one particular inflexible server.
523  }
524 
525  *aZipURL = zip_url.utf8_str();
526  return true;
527  }
528  return false;
529 }
530 
531 
532 void GITHUB_PLUGIN::remoteGetZip( const wxString& aRepoURL ) throw( IO_ERROR )
533 {
534  std::string zip_url;
535 
536  if( !m_zip_image.empty() )
537  return;
538 
539  if( !repoURL_zipURL( aRepoURL, &zip_url ) )
540  {
541  wxString msg = wxString::Format( _( "Unable to parse URL:\n'%s'" ), GetChars( aRepoURL ) );
542  THROW_IO_ERROR( msg );
543  }
544 
545  wxLogDebug( wxT( "Attempting to download: " ) + zip_url );
546 
547  KICAD_CURL_EASY kcurl; // this can THROW_IO_ERROR
548 
549  kcurl.SetURL( zip_url.c_str() );
550  kcurl.SetUserAgent( "http://kicad-pcb.org" );
551  kcurl.SetHeader( "Accept", "application/zip" );
552  kcurl.SetFollowRedirects( true );
553 
554  try
555  {
556  kcurl.Perform();
557  m_zip_image = kcurl.GetBuffer();
558  }
559  catch( const IO_ERROR& ioe )
560  {
561  // https "GET" has failed, report this to API caller.
562  // Note: kcurl.Perform() does not return an error if the file to download is not found
563  static const char errorcmd[] = "http GET command failed"; // Do not translate this message
564 
565  UTF8 fmt( _( "%s\nCannot get/download Zip archive: '%s'\nfor library path: '%s'.\nReason: '%s'" ) );
566 
567  std::string msg = StrPrintf( fmt.c_str(),
568  errorcmd,
569  zip_url.c_str(),
570  TO_UTF8( aRepoURL ),
571  TO_UTF8( ioe.What() )
572  );
573 
574  THROW_IO_ERROR( msg );
575  }
576 
577  // If the zip archive is not existing, the received data is "Not Found" or "404: Not Found",
578  // and no error is returned by kcurl.Perform().
579  if( ( m_zip_image.compare( 0, 9, "Not Found", 9 ) == 0 ) ||
580  ( m_zip_image.compare( 0, 14, "404: Not Found", 14 ) == 0 ) )
581  {
582  UTF8 fmt( _( "Cannot download library '%s'.\nThe library does not exist on the server" ) );
583  std::string msg = StrPrintf( fmt.c_str(), TO_UTF8( aRepoURL ) );
584 
585  THROW_IO_ERROR( msg );
586  }
587 }
588 
589 #if 0 && defined(STANDALONE)
590 
591 int main( int argc, char** argv )
592 {
593  INIT_LOGGER( ".", "test.log" );
594 
595  GITHUB_PLUGIN gh;
596 
597  try
598  {
599  wxArrayString fps = gh.FootprintEnumerate(
600  "https://github.com/liftoff-sr/pretty_footprints",
601  NULL
602  );
603 
604  for( int i=0; i<(int)fps.Count(); ++i )
605  {
606  printf("[%d]:%s\n", i, TO_UTF8( fps[i] ) );
607  }
608  }
609  catch( const IO_ERROR& ioe )
610  {
611  printf( "%s\n", TO_UTF8(ioe.What()) );
612  }
613 
614  UNINIT_LOGGER();
615 
616  return 0;
617 }
618 
619 #endif
Class UTF8 is an 8 bit std::string that is assuredly encoded in UTF8, and supplies special conversion...
Definition: utf8.h:53
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
boost::ptr_map< string, wxZipEntry > MODULE_MAP
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 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 ...
#define THROW_IO_ERROR(x)
Definition: utf8.cpp:60
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:298
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...
wxArrayString FootprintEnumerate(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Function FootprintEnumerate returns a list of footprint names contained within the library at aLibrar...
bool IsFootprintLibWritable(const wxString &aLibraryPath) override
Function IsFootprintLibWritable returns true iff the library at aLibraryPath is writable.
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
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:153
static const char * PRETTY_DIR
const wxString GetFileExtension() const override
Function GetFileExtension returns the file extension for the PLUGIN.
wxArrayString FootprintEnumerate(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Function FootprintEnumerate returns a list of footprint names contained within the library at aLibrar...