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