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 long long GITHUB_PLUGIN::GetLibraryTimestamp( const wxString& aLibraryPath ) const
468 {
469  // This plugin currently relies on the nginx server for caching (see comments
470  // at top of file).
471  // Since only the nginx server holds the timestamp information, we must defeat
472  // all caching above the nginx server.
473  return wxDateTime::Now().GetValue().GetValue();
474 
475 #if 0
476  // If we have no cache, return a number which won't match any stored timestamps
477  if( !m_gh_cache || m_lib_path != aLibraryPath )
478  return wxDateTime::Now().GetValue().GetValue();
479 
480  long long hash = m_gh_cache->GetTimestamp();
481 
482  if( m_pretty_dir.size() )
484 
485  return hash;
486 #endif
487 }
488 
489 
490 bool GITHUB_PLUGIN::repoURL_zipURL( const wxString& aRepoURL, std::string* aZipURL )
491 {
492  // e.g. "https://github.com/liftoff-sr/pretty_footprints"
493  //D(printf("aRepoURL:%s\n", TO_UTF8( aRepoURL ) );)
494 
495  wxURI repo( aRepoURL );
496 
497  if( repo.HasServer() && repo.HasPath() )
498  {
499  // scheme might be "http" or if truly github.com then "https".
500  wxString zip_url;
501 
502  if( repo.GetServer() == "github.com" )
503  {
504  //codeload.github.com only supports https
505  zip_url = "https://";
506 #if 0 // A proper code path would be this one, but it is not the fastest.
507  zip_url += repo.GetServer();
508  zip_url += repo.GetPath(); // path comes with a leading '/'
509  zip_url += "/archive/master.zip";
510 #else
511  // Github issues a redirect for the "master.zip". i.e.
512  // "https://github.com/liftoff-sr/pretty_footprints/archive/master.zip"
513  // would be redirected to:
514  // "https://codeload.github.com/liftoff-sr/pretty_footprints/zip/master"
515 
516  // In order to bypass this redirect, saving time, we use the
517  // redirected URL on first attempt to save one HTTP GET hit.
518  zip_url += "codeload.github.com";
519  zip_url += repo.GetPath(); // path comes with a leading '/'
520  zip_url += "/zip/master";
521 #endif
522  }
523 
524  else
525  {
526  zip_url = repo.GetScheme();
527  zip_url += "://";
528 
529  // This is the generic code path for any server which can serve
530  // up zip files. The schemes tested include: http and https.
531 
532  // zip_url goal: "<scheme>://<server>[:<port>]/<path>"
533 
534  // Remember that <scheme>, <server>, <port> if present, and <path> all came
535  // from the lib_path in the fp-lib-table row.
536 
537  // This code path is used with the nginx proxy setup, but is useful
538  // beyond that.
539 
540  zip_url += repo.GetServer();
541 
542  if( repo.HasPort() )
543  {
544  zip_url += ':';
545  zip_url += repo.GetPort();
546  }
547 
548  zip_url += repo.GetPath(); // path comes with a leading '/'
549 
550  // Do not modify the path, we cannot anticipate the needs of all
551  // servers which are serving up zip files directly. URL modifications
552  // are more generally done in the server, rather than contaminating
553  // this code path with the needs of one particular inflexible server.
554  }
555 
556  *aZipURL = zip_url.utf8_str();
557  return true;
558  }
559  return false;
560 }
561 
562 
563 void GITHUB_PLUGIN::remoteGetZip( const wxString& aRepoURL )
564 {
565  std::string zip_url;
566 
567  if( !m_zip_image.empty() )
568  return;
569 
570  if( !repoURL_zipURL( aRepoURL, &zip_url ) )
571  {
572  wxString msg = wxString::Format( _( "Unable to parse URL:\n\"%s\"" ), GetChars( aRepoURL ) );
573  THROW_IO_ERROR( msg );
574  }
575 
576  wxLogDebug( wxT( "Attempting to download: " ) + zip_url );
577 
578  KICAD_CURL_EASY kcurl; // this can THROW_IO_ERROR
579 
580  kcurl.SetURL( zip_url.c_str() );
581  kcurl.SetUserAgent( "http://kicad-pcb.org" );
582  kcurl.SetHeader( "Accept", "application/zip" );
583  kcurl.SetFollowRedirects( true );
584 
585  try
586  {
587  kcurl.Perform();
588  m_zip_image = kcurl.GetBuffer();
589  }
590  catch( const IO_ERROR& ioe )
591  {
592  // https "GET" has failed, report this to API caller.
593  // Note: kcurl.Perform() does not return an error if the file to download is not found
594  static const char errorcmd[] = "http GET command failed"; // Do not translate this message
595 
596  UTF8 fmt( _( "%s\nCannot get/download Zip archive: \"%s\"\nfor library path: \"%s\".\nReason: \"%s\"" ) );
597 
598  std::string msg = StrPrintf( fmt.c_str(),
599  errorcmd,
600  zip_url.c_str(),
601  TO_UTF8( aRepoURL ),
602  TO_UTF8( ioe.What() )
603  );
604 
605  THROW_IO_ERROR( msg );
606  }
607 
608  // If the zip archive is not existing, the received data is "Not Found" or "404: Not Found",
609  // and no error is returned by kcurl.Perform().
610  if( ( m_zip_image.compare( 0, 9, "Not Found", 9 ) == 0 ) ||
611  ( m_zip_image.compare( 0, 14, "404: Not Found", 14 ) == 0 ) )
612  {
613  UTF8 fmt( _( "Cannot download library \"%s\".\nThe library does not exist on the server" ) );
614  std::string msg = StrPrintf( fmt.c_str(), TO_UTF8( aRepoURL ) );
615 
616  THROW_IO_ERROR( msg );
617  }
618 }
619 
620 #if 0 && defined(STANDALONE)
621 
622 int main( int argc, char** argv )
623 {
624  INIT_LOGGER( ".", "test.log" );
625 
626  GITHUB_PLUGIN gh;
627 
628  try
629  {
630  wxArrayString fps = gh.FootprintEnumerate(
631  "https://github.com/liftoff-sr/pretty_footprints",
632  NULL
633  );
634 
635  for( int i=0; i<(int)fps.Count(); ++i )
636  {
637  printf("[%d]:%s\n", i, TO_UTF8( fps[i] ) );
638  }
639  }
640  catch( const IO_ERROR& ioe )
641  {
642  printf( "%s\n", TO_UTF8(ioe.What()) );
643  }
644 
645  UNINIT_LOGGER();
646 
647  return 0;
648 }
649 
650 #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)
Replaces any environment variable references with their values and is here to fully embellish the TAB...
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.
Template specialization to enable wxStrings for certain containers (e.g. unordered_map) ...
Definition: bitmap.cpp:54
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
long long GetLibraryTimestamp(const wxString &aLibraryPath) const override
Generate a timestamp representing all the files in the library (including the library directory)...
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:74
#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...
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&#39;s PLUGIN interface to provide read only access to ...
std::map< wxString, MODULE * > MODULE_MAP
Definition: eagle_plugin.h:35
boost::ptr_map< wxString, wxZipEntry > MODULE_MAP
wxString m_pretty_dir
PCB_PARSER * m_parser
BOARD_ITEM * Parse()
Definition: pcb_parser.cpp:442
LINE_READER * SetLineReader(LINE_READER *aReader)
Function SetLineReader sets aLineReader into the parser, and returns the previous one...
Definition: pcb_parser.h:289
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
size_t i
Definition: json11.cpp:597
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:131
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:192
static const char * PRETTY_DIR
const wxString GetFileExtension() const override
Function GetFileExtension returns the file extension for the PLUGIN.