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