summaryrefslogtreecommitdiff
path: root/pcbnew/github
diff options
context:
space:
mode:
Diffstat (limited to 'pcbnew/github')
-rw-r--r--pcbnew/github/CMakeLists.txt50
-rw-r--r--pcbnew/github/avhttp-master.zipbin0 -> 173539 bytes
-rw-r--r--pcbnew/github/github_getliblist.cpp242
-rw-r--r--pcbnew/github/github_getliblist.h124
-rw-r--r--pcbnew/github/github_plugin.cpp599
-rw-r--r--pcbnew/github/github_plugin.h229
-rw-r--r--pcbnew/github/html_link_parser.cpp69
-rw-r--r--pcbnew/github/html_link_parser.h109
-rw-r--r--pcbnew/github/nginx.conf64
9 files changed, 1486 insertions, 0 deletions
diff --git a/pcbnew/github/CMakeLists.txt b/pcbnew/github/CMakeLists.txt
new file mode 100644
index 0000000..e9c8b9c
--- /dev/null
+++ b/pcbnew/github/CMakeLists.txt
@@ -0,0 +1,50 @@
+# This program source code file is part of KICAD, a free EDA CAD application.
+#
+# Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
+# Copyright (C) 2013 Kicad Developers, see AUTHORS.txt for contributors.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, you may find one here:
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+# or you may search the http://www.gnu.org website for the version 2 license,
+# or you may write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+
+
+# These are additions to any inherited from pcbnew dir:
+include_directories( . )
+
+include_directories( ${CURL_INCLUDE_DIRS} )
+
+set( GITHUB_PLUGIN_SRCS
+ github_plugin.cpp
+ github_getliblist.cpp
+ html_link_parser.cpp
+ )
+
+add_library( github_plugin STATIC ${GITHUB_PLUGIN_SRCS} )
+
+target_link_libraries( github_plugin
+ common
+ )
+
+if( MINGW )
+ target_link_libraries( github_plugin
+ ${wxWidgets_LIBRARIES}
+ ws2_32
+ )
+endif()
+
+add_dependencies( github_plugin boost )
+
diff --git a/pcbnew/github/avhttp-master.zip b/pcbnew/github/avhttp-master.zip
new file mode 100644
index 0000000..2fa261a
--- /dev/null
+++ b/pcbnew/github/avhttp-master.zip
Binary files differ
diff --git a/pcbnew/github/github_getliblist.cpp b/pcbnew/github/github_getliblist.cpp
new file mode 100644
index 0000000..15c321a
--- /dev/null
+++ b/pcbnew/github/github_getliblist.cpp
@@ -0,0 +1,242 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2015 Jean-Pierre Charras jp.charras at wanadoo.fr
+ * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
+ * Copyright (C) 2015 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+
+/*
+ * While creating a wizard to edit the fp lib tables, and mainly the web viewer
+ * which can read the list of pretty library on a github repos, I was told there is
+ * this URL to retrieve info from any particular repo:
+ *
+ * https://api.github.com/orgs/KiCad/repos
+ * or
+ * https://api.github.com/users/KiCad/repos
+ *
+ * This gets just information on the repo in JSON format.
+ *
+ * JP Charras.
+ */
+
+#include <kicad_curl/kicad_curl_easy.h> // Include before any wx file
+#include <wx/uri.h>
+
+#include <github_getliblist.h>
+#include <macros.h>
+#include <common.h>
+#include <html_link_parser.h>
+
+
+GITHUB_GETLIBLIST::GITHUB_GETLIBLIST( const wxString& aRepoURL )
+{
+ m_repoURL = aRepoURL;
+ m_libs_ext = wxT( ".pretty" );
+ strcpy( m_option_string, "application/json" );
+}
+
+
+bool GITHUB_GETLIBLIST::Get3DshapesLibsList( wxArrayString* aList,
+ bool (*aFilter)( const wxString& aData ) )
+{
+ std::string fullURLCommand;
+
+ strcpy( m_option_string, "text/html" );
+
+ wxString repoURL = m_repoURL;
+
+ wxString errorMsg;
+
+ fullURLCommand = repoURL.utf8_str();
+ bool success = remoteGetJSON( fullURLCommand, &errorMsg );
+
+ if( !success )
+ {
+ wxMessageBox( errorMsg );
+ return false;
+ }
+
+ if( aFilter && aList )
+ {
+ //Convert m_image (std::string) to a wxString for HTML_LINK_PARSER
+ wxString buffer( GetBuffer() );
+
+ HTML_LINK_PARSER html_parser( buffer, *aList );
+ html_parser.ParseLinks( aFilter );
+ }
+
+ return true;
+}
+
+
+bool GITHUB_GETLIBLIST::GetFootprintLibraryList( wxArrayString& aList )
+{
+ std::string fullURLCommand;
+ int page = 1;
+ int itemCountMax = 99; // Do not use a valu > 100, it does not work
+
+ strcpy( m_option_string, "application/json" );
+
+ // Github max items returned is 100 per page
+
+ if( !repoURL2listURL( m_repoURL, &fullURLCommand, itemCountMax, page ) )
+ {
+ wxString msg = wxString::Format( _( "malformed URL:\n'%s'" ), GetChars( m_repoURL ) );
+ wxMessageBox( msg );
+ return false;
+ }
+
+ // The URL lib names are relative to the server name.
+ // so add the server name to them.
+ wxURI repo( m_repoURL );
+ wxString urlPrefix = repo.GetScheme() + wxT( "://" ) + repo.GetServer() + wxT( "/" );
+
+ wxString errorMsg;
+ const char sep = ','; // Separator fields, in json returned file
+ wxString tmp;
+ int items_count_per_page = 0;
+ std::string& json_image = GetBuffer();
+
+ while( 1 )
+ {
+ bool success = remoteGetJSON( fullURLCommand, &errorMsg );
+
+ if( !success )
+ {
+ wxMessageBox( errorMsg );
+ return false;
+ }
+
+
+ for( unsigned ii = 0; ii < json_image.size(); ii++ )
+ {
+ if( json_image[ii] == sep || ii == json_image.size() - 1 )
+ {
+ if( tmp.StartsWith( wxT( "\"full_name\"" ) ) )
+ {
+ #define QUOTE '\"'
+ // Remove useless quotes:
+ if( tmp[tmp.Length() - 1] == QUOTE )
+ tmp.RemoveLast();
+
+ if( tmp.EndsWith( m_libs_ext ) )
+ {
+ aList.Add( tmp.AfterLast( ':' ) );
+ int idx = aList.GetCount() - 1;
+
+ if( aList[idx][0] == QUOTE )
+ aList[idx].Remove( 0, 1 );
+
+ aList[idx].Prepend( urlPrefix );
+ }
+
+ items_count_per_page++;
+ }
+
+ tmp.Clear();
+ }
+ else
+ tmp << json_image[ii];
+ }
+
+ if( items_count_per_page >= itemCountMax )
+ {
+ page++;
+ repoURL2listURL( m_repoURL, &fullURLCommand, itemCountMax, page );
+ items_count_per_page = 0;
+ ClearBuffer();
+ }
+ else
+ break;
+ }
+
+ aList.Sort();
+ return true;
+}
+
+
+bool GITHUB_GETLIBLIST::repoURL2listURL( const wxString& aRepoURL,
+ std::string* aFullURLCommand,
+ int aItemCountMax, int aPage )
+{
+ // aListURL is e.g. "https://api.github.com/orgs/KiCad/repos"
+ // or "https://api.github.com/users/KiCad/repos"
+ // aRepoURL is e.g. "https://github.com/KiCad"
+ // Github has a default pagination set to 30 items.
+ // but allows up to 100 items max if we add the "?per_page=100" option
+
+ wxURI repo( aRepoURL );
+
+ if( repo.HasServer() && repo.HasPath() )
+ {
+ // goal: "https://api.github.com/users/KiCad"
+ // or "https://api.github.com/orgs/KiCad"
+ // "https://api.github.com/users/..." works both for orgs and users
+ // if we just retrieve the .pretty list
+ wxString target_url( wxT( "https://api.github.com/users" ) );
+ target_url += repo.GetPath();
+ target_url += wxT( "/repos" );
+
+ // Github has a default pagination set to 30 items.
+ // but allows up to 100 items max. Use this limit
+ target_url += wxString::Format( "?per_page=%d&page=%d", aItemCountMax, aPage );
+
+ *aFullURLCommand = target_url.utf8_str();
+ return true;
+ }
+
+ return false;
+}
+
+
+bool GITHUB_GETLIBLIST::remoteGetJSON( const std::string& aFullURLCommand, wxString* aMsgError )
+{
+ KICAD_CURL_EASY kcurl;
+
+ wxLogDebug( wxT( "Attempting to download: " ) + aFullURLCommand );
+
+ kcurl.SetURL( aFullURLCommand );
+ kcurl.SetUserAgent( "http://kicad-pcb.org" );
+ kcurl.SetHeader( "Accept", m_option_string );
+ kcurl.SetFollowRedirects( true );
+
+ try
+ {
+ kcurl.Perform();
+ m_image = kcurl.GetBuffer();
+ return true;
+ }
+ catch( const IO_ERROR& ioe )
+ {
+ if( aMsgError )
+ {
+ UTF8 fmt( _( "Error fetching JSON data from URL '%s'.\nReason: '%s'" ) );
+
+ std::string msg = StrPrintf( fmt.c_str(),
+ aFullURLCommand.c_str(),
+ TO_UTF8( ioe.errorText ) );
+
+ *aMsgError = FROM_UTF8( msg.c_str() );
+ }
+ return false;
+ }
+}
diff --git a/pcbnew/github/github_getliblist.h b/pcbnew/github/github_getliblist.h
new file mode 100644
index 0000000..0d38b8a
--- /dev/null
+++ b/pcbnew/github/github_getliblist.h
@@ -0,0 +1,124 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2015 Jean-Pierre Charras jp.charras at wanadoo.fr
+ * Copyright (C) 2015 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef GITHUB_GETLIBLIST_H_
+#define GITHUB_GETLIBLIST_H_
+
+
+/**
+ * Class GITHUB_GETLIBLIST
+ * implements a portion of pcbnew's PLUGIN interface to provide read only access
+ * to a github repo to extract pretty footprints library list, in json format,
+ * or extract 3D shapes libraries list (.3dshapes folders) and download the 3d shapes files
+ *
+ * To extract pretty footprints library list, this plugin simply reads in
+ * a zip file of the repo and unzips it from RAM as needed.
+ * Therefore this "Github" plugin is <b>read only for accessing remote
+ * at https://api.github.com/orgs/KiCad/repos</b>
+ *
+ * To extract 3D shapes libraries list (.3dshapes folders) we cannot use api.github.com
+ * to read this list, becuse it is in a subdirectory of https://github.com/KiCad.
+ * The corresponding html page of the server is read, and URLs of all .3dshapes folders
+ * are extracted.
+ * files are then read from https://raw.githubusercontent.com/<lib path>, but not zipped
+ * because they are not accessible in zipped form.
+ */
+class GITHUB_GETLIBLIST
+{
+public:
+ // -----<API>----------------------------------------------------------
+
+ /**
+ * Fills aList by the name of footprint libraries found on the github repo
+ */
+ bool GetFootprintLibraryList( wxArrayString& aList );
+
+ /**
+ * Fills aList by the URL of libraries found on the github repo
+ * @param aList = a reference to a wxArrayString to fill with names
+ * @param aFilter( const wxString& aData ) = a callback funtion to
+ * to filter URLs to put in aList.
+ * If NULL, no URL will be stored in aList
+ */
+ bool Get3DshapesLibsList( wxArrayString* aList,
+ bool (*aFilter)( const wxString& aData ) );
+
+ /**
+ * @return the buffer which stores all the downloaded raw data
+ */
+ std::string& GetBuffer() { return m_image; }
+
+ /**
+ * Clear the buffer which stores all the downloaded raw data
+ */
+ void ClearBuffer() { m_image.clear(); }
+
+ /**
+ * The library names are expecting ending by .pretty
+ * SetLibraryExt set the extension to aExt
+ */
+ void SetLibraryExt( const wxString& aExt ) { m_libs_ext = aExt; }
+
+ // -----</API>---------------------------------------------------------
+
+ GITHUB_GETLIBLIST( const wxString& aRepoURL );
+ ~GITHUB_GETLIBLIST() {}
+
+protected:
+
+ /**
+ * Function repoURL2listURL
+ * translates a repo URL to the URL name which gives the state of repos URL
+ * as commonly seen on github.com
+ *
+ * @param aRepoURL points to the base of the repo.
+ * @param aFullURLCommand is URL the full URL command (URL+options).
+ * @param aItemCountMax is the max item count in a page,
+ * and is 100 for github repo.
+ * @param aPage is the page number, if there are more than one page in repo.
+ * @return bool - true if @a aRepoULR was parseable, else false
+ */
+ bool repoURL2listURL( const wxString& aRepoURL, std::string* aFullURLCommand,
+ int aItemCountMax, int aPage = 1 );
+
+ /**
+ * Function remoteGetJSON
+ * Download a json text from a github repo. The text image
+ * is received into the m_input_stream.
+ * @param aFullURLCommand the full command, i.e. the url with options like
+ * "https://api.github.com/users/KiCad/repos?per_page=100?page=1"
+ * @param aMsgError a pointer to a wxString which can store an error message
+ * @return true if OK, false if error (which an error message in *aMsgError
+ */
+ bool remoteGetJSON( const std::string& aFullURLCommand, wxString* aMsgError );
+
+ wxString m_github_path; ///< Something like https://api.github.com/orgs/KiCad
+ std::string m_image; ///< image of the downloaded data in its entirety.
+ wxString m_repoURL; ///< the URL of the Github repo
+ wxString m_libs_ext; ///< the extension of the name of libraries (default = .pretty)
+ char m_option_string[64]; ///< option for transfert type, like "application/json"
+};
+
+
+#endif // GITHUB_GETLIBLIST_H_
diff --git a/pcbnew/github/github_plugin.cpp b/pcbnew/github/github_plugin.cpp
new file mode 100644
index 0000000..0981083
--- /dev/null
+++ b/pcbnew/github/github_plugin.cpp
@@ -0,0 +1,599 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
+ * Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+
+/*
+
+While exploring the possibility of local caching of the zip file, I discovered
+this command to retrieve the time stamp of the last commit into any particular
+repo:
+
+ $time curl -I -i https://api.github.com/repos/KiCad/Mounting_Holes.pretty/commits
+
+This gets just the header to what would otherwise return information on the repo
+in JSON format, and is reasonably faster than actually getting the repo
+in zip form. However it still takes 5 seconds or more when github is busy, so
+I have lost my enthusiasm for local caching until a faster time stamp retrieval
+mechanism can be found, or github gets more servers. But note that the occasionally
+slow response is the exception rather than the norm. Normally the response is
+down around a 1/3 of a second. The information we would use is in the header
+named "Last-Modified" as seen below.
+
+
+HTTP/1.1 200 OK
+Server: GitHub.com
+Date: Mon, 27 Jan 2014 15:46:46 GMT
+Content-Type: application/json; charset=utf-8
+Status: 200 OK
+X-RateLimit-Limit: 60
+X-RateLimit-Remaining: 49
+X-RateLimit-Reset: 1390839612
+Cache-Control: public, max-age=60, s-maxage=60
+Last-Modified: Mon, 02 Dec 2013 10:08:51 GMT
+ETag: "3d04d760f469f2516a51a56eac63bbd5"
+Vary: Accept
+X-GitHub-Media-Type: github.beta
+X-Content-Type-Options: nosniff
+Content-Length: 6310
+Access-Control-Allow-Credentials: true
+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
+Access-Control-Allow-Origin: *
+X-GitHub-Request-Id: 411087C2:659E:50FD6E6:52E67F66
+Vary: Accept-Encoding
+*/
+
+#include <kicad_curl/kicad_curl_easy.h> // Include before any wx file
+#include <sstream>
+#include <boost/ptr_container/ptr_map.hpp>
+#include <set>
+
+#include <wx/zipstrm.h>
+#include <wx/mstream.h>
+#include <wx/uri.h>
+
+#include <fctsys.h>
+
+#include <io_mgr.h>
+#include <richio.h>
+#include <pcb_parser.h>
+#include <class_board.h>
+#include <github_plugin.h>
+#include <class_module.h>
+#include <macros.h>
+#include <fp_lib_table.h> // ExpandSubstitutions()
+#include <github_getliblist.h>
+
+
+using namespace std;
+
+
+static const char* PRETTY_DIR = "allow_pretty_writing_to_this_dir";
+
+
+typedef boost::ptr_map<string, wxZipEntry> MODULE_MAP;
+typedef MODULE_MAP::iterator MODULE_ITER;
+typedef MODULE_MAP::const_iterator MODULE_CITER;
+
+
+/**
+ * Class GH_CACHE
+ * assists only within GITHUB_PLUGIN and holds a map of footprint name to wxZipEntry
+ */
+struct GH_CACHE : public MODULE_MAP
+{
+ // MODULE_MAP is a boost::ptr_map template, made into a class hereby.
+};
+
+
+GITHUB_PLUGIN::GITHUB_PLUGIN() :
+ PCB_IO(),
+ m_gh_cache( 0 )
+{
+}
+
+
+GITHUB_PLUGIN::~GITHUB_PLUGIN()
+{
+ delete m_gh_cache;
+}
+
+
+const wxString GITHUB_PLUGIN::PluginName() const
+{
+ return "Github";
+}
+
+
+const wxString GITHUB_PLUGIN::GetFileExtension() const
+{
+ return wxEmptyString;
+}
+
+
+wxArrayString GITHUB_PLUGIN::FootprintEnumerate(
+ const wxString& aLibraryPath, const PROPERTIES* aProperties )
+{
+ //D(printf("%s: this:%p aLibraryPath:'%s'\n", __func__, this, TO_UTF8(aLibraryPath) );)
+ cacheLib( aLibraryPath, aProperties );
+
+ typedef std::set<wxString> MYSET;
+
+ MYSET unique;
+
+ if( m_pretty_dir.size() )
+ {
+ wxArrayString locals = PCB_IO::FootprintEnumerate( m_pretty_dir );
+
+ for( unsigned i=0; i<locals.GetCount(); ++i )
+ unique.insert( locals[i] );
+ }
+
+ for( MODULE_ITER it = m_gh_cache->begin(); it!=m_gh_cache->end(); ++it )
+ {
+ unique.insert( FROM_UTF8( it->first.c_str() ) );
+ }
+
+ wxArrayString ret;
+
+ for( MYSET::const_iterator it = unique.begin(); it != unique.end(); ++it )
+ {
+ ret.Add( *it );
+ }
+
+ return ret;
+}
+
+
+MODULE* GITHUB_PLUGIN::FootprintLoad( const wxString& aLibraryPath,
+ const wxString& aFootprintName, const PROPERTIES* aProperties )
+{
+ // D(printf("%s: this:%p aLibraryPath:'%s'\n", __func__, this, TO_UTF8(aLibraryPath) );)
+
+ // clear or set to valid the variable m_pretty_dir
+ cacheLib( aLibraryPath, aProperties );
+
+ if( m_pretty_dir.size() )
+ {
+ // API has FootprintLoad() *not* throwing an exception if footprint not found.
+ MODULE* local = PCB_IO::FootprintLoad( m_pretty_dir, aFootprintName, aProperties );
+
+ if( local )
+ {
+ // It has worked, see <src>/scripts/test_kicad_plugin.py. So this was not firing:
+ // wxASSERT( aFootprintName == FROM_UTF8( local->GetFPID().GetFootprintName().c_str() ) );
+ // Moving it to higher API layer FP_LIB_TABLE::FootprintLoad().
+
+ return local;
+ }
+ }
+
+ UTF8 fp_name = aFootprintName;
+
+ MODULE_CITER it = m_gh_cache->find( fp_name );
+
+ if( it != m_gh_cache->end() ) // fp_name is present
+ {
+ //std::string::data() ensures that the referenced data block is contiguous.
+ wxMemoryInputStream mis( m_zip_image.data(), m_zip_image.size() );
+
+ // This decoder should always be UTF8, since it was saved that way by git.
+ // That is, since pretty footprints are UTF8, and they were pushed to the
+ // github repo, they are still UTF8.
+ wxZipInputStream zis( mis, wxConvUTF8 );
+ wxZipEntry* entry = (wxZipEntry*) it->second; // remove "const"-ness
+
+ if( zis.OpenEntry( *entry ) )
+ {
+ INPUTSTREAM_LINE_READER reader( &zis, aLibraryPath );
+
+ // I am a PCB_IO derivative with my own PCB_PARSER
+ m_parser->SetLineReader( &reader ); // ownership not passed
+
+ MODULE* ret = (MODULE*) m_parser->Parse();
+
+ // In a github library, (as well as in a "KiCad" library) the name of
+ // the pretty file defines the footprint name. That filename trumps
+ // any name found in the pretty file; any name in the pretty file
+ // must be ignored here. Also, the library nickname is unknown in
+ // this context so clear it just in case.
+ ret->SetFPID( fp_name );
+
+ return ret;
+ }
+ }
+
+ return NULL; // this API function returns NULL for "not found", per spec.
+}
+
+
+bool GITHUB_PLUGIN::IsFootprintLibWritable( const wxString& aLibraryPath )
+{
+ if( m_pretty_dir.size() )
+ return PCB_IO::IsFootprintLibWritable( m_pretty_dir );
+ else
+ return false;
+}
+
+
+void GITHUB_PLUGIN::FootprintSave( const wxString& aLibraryPath,
+ const MODULE* aFootprint, const PROPERTIES* aProperties )
+{
+ // set m_pretty_dir to either empty or something in aProperties
+ cacheLib( aLibraryPath, aProperties );
+
+ if( GITHUB_PLUGIN::IsFootprintLibWritable( aLibraryPath ) )
+ {
+ PCB_IO::FootprintSave( m_pretty_dir, aFootprint, aProperties );
+ }
+ else
+ {
+ // This typically will not happen if the caller first properly calls
+ // IsFootprintLibWritable() to determine if calling FootprintSave() is
+ // even legal, so I spend no time on internationalization here:
+
+ string msg = StrPrintf( "Github library\n'%s'\nis only writable if you set option '%s' in Library Tables dialog.",
+ TO_UTF8( aLibraryPath ), PRETTY_DIR );
+
+ THROW_IO_ERROR( msg );
+ }
+}
+
+
+void GITHUB_PLUGIN::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName,
+ const PROPERTIES* aProperties )
+{
+ // set m_pretty_dir to either empty or something in aProperties
+ cacheLib( aLibraryPath, aProperties );
+
+ if( GITHUB_PLUGIN::IsFootprintLibWritable( aLibraryPath ) )
+ {
+ // Does the PCB_IO base class have this footprint?
+ // We cannot write to github.
+
+ wxArrayString pretties = PCB_IO::FootprintEnumerate( m_pretty_dir, aProperties );
+
+ if( pretties.Index( aFootprintName ) != wxNOT_FOUND )
+ {
+ PCB_IO::FootprintDelete( m_pretty_dir, aFootprintName, aProperties );
+ }
+ else
+ {
+ wxString msg = wxString::Format(
+ _( "Footprint\n'%s'\nis not in the writable portion of this Github library\n'%s'" ),
+ GetChars( aFootprintName ),
+ GetChars( aLibraryPath )
+ );
+
+ THROW_IO_ERROR( msg );
+ }
+ }
+ else
+ {
+ // This typically will not happen if the caller first properly calls
+ // IsFootprintLibWritable() to determine if calling FootprintSave() is
+ // even legal, so I spend no time on internationalization here:
+
+ string msg = StrPrintf( "Github library\n'%s'\nis only writable if you set option '%s' in Library Tables dialog.",
+ TO_UTF8( aLibraryPath ), PRETTY_DIR );
+
+ THROW_IO_ERROR( msg );
+ }
+}
+
+
+void GITHUB_PLUGIN::FootprintLibCreate( const wxString& aLibraryPath, const PROPERTIES* aProperties )
+{
+ // set m_pretty_dir to either empty or something in aProperties
+ cacheLib( aLibraryPath, aProperties );
+
+ if( m_pretty_dir.size() )
+ {
+ PCB_IO::FootprintLibCreate( m_pretty_dir, aProperties );
+ }
+ else
+ {
+ // THROW_IO_ERROR() @todo
+ }
+}
+
+
+bool GITHUB_PLUGIN::FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties )
+{
+ // set m_pretty_dir to either empty or something in aProperties
+ cacheLib( aLibraryPath, aProperties );
+
+ if( m_pretty_dir.size() )
+ {
+ return PCB_IO::FootprintLibDelete( m_pretty_dir, aProperties );
+ }
+ else
+ {
+ // THROW_IO_ERROR() @todo
+ return false;
+ }
+}
+
+
+void GITHUB_PLUGIN::FootprintLibOptions( PROPERTIES* aListToAppendTo ) const
+{
+ // inherit options supported by all PLUGINs.
+ PLUGIN::FootprintLibOptions( aListToAppendTo );
+
+ (*aListToAppendTo)[ PRETTY_DIR ] = UTF8( _(
+ "Set this property to a directory where footprints are to be written as pretty "
+ "footprints when saving to this library. Anything saved will take precedence over "
+ "footprints by the same name in the github repo. These saved footprints can then "
+ "be sent to the library maintainer as updates. "
+ "<p>The directory <b>must</b> have a <b>.pretty</b> file extension because the "
+ "format of the save is pretty.</p>"
+ ));
+
+ /*
+ (*aListToAppendTo)["cache_github_zip_in_this_dir"] = UTF8( _(
+ "Set this property to a directory where the github *.zip file will be cached. "
+ "This should speed up subsequent visits to this library."
+ ));
+ */
+}
+
+
+void GITHUB_PLUGIN::cacheLib( const wxString& aLibraryPath, const PROPERTIES* aProperties )
+{
+ // This is edge triggered based on a change in 'aLibraryPath',
+ // usually it does nothing. When the edge fires, m_pretty_dir is set
+ // to either:
+ // 1) empty or
+ // 2) a verified and validated, writable, *.pretty directory.
+
+ if( !m_gh_cache || m_lib_path != aLibraryPath )
+ {
+ delete m_gh_cache;
+ m_gh_cache = 0;
+
+ m_pretty_dir.clear();
+
+ if( aProperties )
+ {
+ UTF8 pretty_dir;
+
+ if( aProperties->Value( PRETTY_DIR, &pretty_dir ) )
+ {
+ wxString wx_pretty_dir = pretty_dir;
+
+ wx_pretty_dir = FP_LIB_TABLE::ExpandSubstitutions( wx_pretty_dir );
+
+ wxFileName wx_pretty_fn = wx_pretty_dir;
+
+ if( !wx_pretty_fn.IsOk() ||
+ !wx_pretty_fn.IsDirWritable() ||
+ wx_pretty_fn.GetExt() != "pretty"
+ )
+ {
+ wxString msg = wxString::Format(
+ _( "option '%s' for Github library '%s' must point to a writable directory ending with '.pretty'." ),
+ GetChars( FROM_UTF8( PRETTY_DIR ) ),
+ GetChars( aLibraryPath )
+ );
+
+ THROW_IO_ERROR( msg );
+ }
+
+ m_pretty_dir = wx_pretty_dir;
+ }
+ }
+
+ // operator==( wxString, wxChar* ) does not exist, construct wxString once here.
+ const wxString kicad_mod( "kicad_mod" );
+
+ //D(printf("%s: this:%p m_lib_path:'%s' aLibraryPath:'%s'\n", __func__, this, TO_UTF8( m_lib_path), TO_UTF8(aLibraryPath) );)
+ m_gh_cache = new GH_CACHE();
+
+ // INIT_LOGGER( "/tmp", "test.log" );
+ remoteGetZip( aLibraryPath );
+ // UNINIT_LOGGER();
+
+ m_lib_path = aLibraryPath;
+
+ wxMemoryInputStream mis( &m_zip_image[0], m_zip_image.size() );
+
+ // @todo: generalize this name encoding from a PROPERTY (option) later
+ wxZipInputStream zis( mis, wxConvUTF8 );
+
+ wxZipEntry* entry;
+
+ while( ( entry = zis.GetNextEntry() ) != NULL )
+ {
+ wxFileName fn( entry->GetName() ); // chop long name into parts
+
+ if( fn.GetExt() == kicad_mod )
+ {
+ UTF8 fp_name = fn.GetName(); // omit extension & path
+
+ m_gh_cache->insert( fp_name, entry );
+ }
+ else
+ delete entry;
+ }
+ }
+}
+
+
+bool GITHUB_PLUGIN::repoURL_zipURL( const wxString& aRepoURL, std::string* aZipURL )
+{
+ // e.g. "https://github.com/liftoff-sr/pretty_footprints"
+ //D(printf("aRepoURL:%s\n", TO_UTF8( aRepoURL ) );)
+
+ wxURI repo( aRepoURL );
+
+ if( repo.HasServer() && repo.HasPath() )
+ {
+ // scheme might be "http" or if truly github.com then "https".
+ wxString zip_url;
+
+ if( repo.GetServer() == "github.com" )
+ {
+ //codeload.github.com only supports https
+ zip_url = "https://";
+#if 0 // A proper code path would be this one, but it is not the fastest.
+ zip_url += repo.GetServer();
+ zip_url += repo.GetPath(); // path comes with a leading '/'
+ zip_url += "/archive/master.zip";
+#else
+ // Github issues a redirect for the "master.zip". i.e.
+ // "https://github.com/liftoff-sr/pretty_footprints/archive/master.zip"
+ // would be redirected to:
+ // "https://codeload.github.com/liftoff-sr/pretty_footprints/zip/master"
+
+ // In order to bypass this redirect, saving time, we use the
+ // redirected URL on first attempt to save one HTTP GET hit.
+ zip_url += "codeload.github.com";
+ zip_url += repo.GetPath(); // path comes with a leading '/'
+ zip_url += "/zip/master";
+#endif
+ }
+
+ else
+ {
+ zip_url = repo.GetScheme();
+ zip_url += "://";
+
+ // This is the generic code path for any server which can serve
+ // up zip files. The schemes tested include: http and https.
+
+ // zip_url goal: "<scheme>://<server>[:<port>]/<path>"
+
+ // Remember that <scheme>, <server>, <port> if present, and <path> all came
+ // from the lib_path in the fp-lib-table row.
+
+ // This code path is used with the nginx proxy setup, but is useful
+ // beyond that.
+
+ zip_url += repo.GetServer();
+
+ if( repo.HasPort() )
+ {
+ zip_url += ':';
+ zip_url += repo.GetPort();
+ }
+
+ zip_url += repo.GetPath(); // path comes with a leading '/'
+
+ // Do not modify the path, we cannot anticipate the needs of all
+ // servers which are serving up zip files directly. URL modifications
+ // are more generally done in the server, rather than contaminating
+ // this code path with the needs of one particular inflexible server.
+ }
+
+ *aZipURL = zip_url.utf8_str();
+ return true;
+ }
+ return false;
+}
+
+
+void GITHUB_PLUGIN::remoteGetZip( const wxString& aRepoURL ) throw( IO_ERROR )
+{
+ std::string zip_url;
+
+ if( !repoURL_zipURL( aRepoURL, &zip_url ) )
+ {
+ wxString msg = wxString::Format( _( "Unable to parse URL:\n'%s'" ), GetChars( aRepoURL ) );
+ THROW_IO_ERROR( msg );
+ }
+
+ wxLogDebug( wxT( "Attempting to download: " ) + zip_url );
+
+ KICAD_CURL_EASY kcurl; // this can THROW_IO_ERROR
+
+ kcurl.SetURL( zip_url.c_str() );
+ kcurl.SetUserAgent( "http://kicad-pcb.org" );
+ kcurl.SetHeader( "Accept", "application/zip" );
+ kcurl.SetFollowRedirects( true );
+
+ try
+ {
+ kcurl.Perform();
+ m_zip_image = kcurl.GetBuffer();
+ }
+ catch( const IO_ERROR& ioe )
+ {
+ // https "GET" has failed, report this to API caller.
+ // Note: kcurl.Perform() does not return an error if the file to download is not found
+ static const char errorcmd[] = "http GET command failed"; // Do not translate this message
+
+ UTF8 fmt( _( "%s\nCannot get/download Zip archive: '%s'\nfor library path: '%s'.\nReason: '%s'" ) );
+
+ std::string msg = StrPrintf( fmt.c_str(),
+ errorcmd,
+ zip_url.c_str(),
+ TO_UTF8( aRepoURL ),
+ TO_UTF8( ioe.errorText )
+ );
+
+ THROW_IO_ERROR( msg );
+ }
+
+ // If the zip archive is not existing, the received data is "Not Found" or "404: Not Found",
+ // and no error is returned by kcurl.Perform().
+ if( ( m_zip_image.compare( 0, 9, "Not Found", 9 ) == 0 ) ||
+ ( m_zip_image.compare( 0, 14, "404: Not Found", 14 ) == 0 ) )
+ {
+ UTF8 fmt( _( "Cannot download library '%s'.\nThe library does not exist on the server" ) );
+ std::string msg = StrPrintf( fmt.c_str(), TO_UTF8( aRepoURL ) );
+
+ THROW_IO_ERROR( msg );
+ }
+}
+
+#if 0 && defined(STANDALONE)
+
+int main( int argc, char** argv )
+{
+ INIT_LOGGER( ".", "test.log" );
+
+ GITHUB_PLUGIN gh;
+
+ try
+ {
+ wxArrayString fps = gh.FootprintEnumerate(
+ "https://github.com/liftoff-sr/pretty_footprints",
+ NULL
+ );
+
+ for( int i=0; i<(int)fps.Count(); ++i )
+ {
+ printf("[%d]:%s\n", i, TO_UTF8( fps[i] ) );
+ }
+ }
+ catch( const IO_ERROR& ioe )
+ {
+ printf( "%s\n", TO_UTF8(ioe.errorText) );
+ }
+
+ UNINIT_LOGGER();
+
+ return 0;
+}
+
+#endif
diff --git a/pcbnew/github/github_plugin.h b/pcbnew/github/github_plugin.h
new file mode 100644
index 0000000..92f2c13
--- /dev/null
+++ b/pcbnew/github/github_plugin.h
@@ -0,0 +1,229 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
+ * Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef GITHUB_PLUGIN_H_
+#define GITHUB_PLUGIN_H_
+
+#include <kicad_plugin.h>
+
+struct GH_CACHE;
+
+
+/**
+ Class GITHUB_PLUGIN
+ implements a portion of pcbnew's PLUGIN interface to provide read only access
+ to a github repo consisting of pretty footprints, and optionally provides "Copy On Write"
+ support of edited footprints.
+
+ <p>It could have used version 3 of the github.com API documented here:
+
+ <pre>
+ http://developer.github.com/v3/
+ https://help.github.com/articles/creating-an-access-token-for-command-line-use
+ </pre>
+
+ but it does not, since a better technique was discovered. Cleverly this
+ plugin simply reads in a zip file of the repo and unzips it from RAM as
+ needed. Therefore this "Github" plugin is <b>read only for accessing remote
+ pretty libraries at https://github.com.</b>
+
+ <p>The fp-lib-table dialog is entered via menu choice "Preferences | Library
+ Tables". For easy options editing in the current row, click on the "Edit
+ Options" button. The "Library Path" in the fp-lib-table row for a Github
+ library should be set to the full https:// URL.
+
+ <p>For example:
+
+ <pre>
+ https://github.com/liftoff-sr/pretty_footprints
+ </pre>
+
+ This is typically
+
+ <pre>
+ https://github.com/user_name/repo_name
+ </pre>
+ <p>
+
+ The "Plugin Type" should be set to "Github".
+
+ <p>This plugin also supports "Copy On Write", a.k.a. "COW". Thus a Github
+ library may take an optional option called
+ <b>allow_pretty_writing_to_this_dir</b>. This option is essentially the
+ "Library Path" for a local "KiCad" (pretty) type library which is combined to
+ make up the Github library found in the same fp-lib-table row. If the option
+ is missing, then the Github library is read only as always. If the option is
+ present for a Github library, then any writes to this hybrid library will go
+ to the local *.pretty directory. Note that the github.com resident portion of
+ this hybrid COW library is always read only, meaning you cannot delete
+ anything or modify any footprint at github directly. The aggregate library
+ type remains "Github" in your discussions, but it consists of a local R/W
+ portion and a remote R/O portion.
+
+ <p>Below is an fp-lib-table entry for the case without option
+ <b>allow_pretty_writing_to_this_dir</b>:
+
+ <table>
+ <tr>
+ <th>Nickname</th><th>Library Path</th><th>Plugin Type</th><th>Options</th><th>Description</th>
+ </tr>
+
+ <tr>
+ <td>github</td><td>https://github.com/liftoff-sr/pretty_footprints</td><td>Github</td>
+ <td></td><td>Liftoff's GH footprints</td>
+ </tr>
+ </table>
+
+ Below is an fp-lib-table entry with the COW option given. Note the use of the environment variable
+ ${HOME}, as an example only. The github.pretty directory is based in ${HOME}/pretty/. Anytime you
+ use option allow_pretty_writing_to_this_dir, you will create that directory manually and it must
+ end in extension <b>.pretty</b>.
+
+ <table>
+ <tr>
+ <th>Nickname</th><th>Library Path</th><th>Plugin Type</th><th>Options</th><th>Description</th>
+ </tr>
+
+ <tr>
+
+ <td>github</td><td>https://github.com/liftoff-sr/pretty_footprints</td><td>Github</td>
+ <td>allow_pretty_writing_to_this_dir=${HOME}/pretty/github.pretty</td>
+ <td>Liftoff's GH footprints</td>
+ </tr>
+ </table>
+
+ <p>Any footprint loads will always give precedence to the local footprints
+ found in the pretty dir given by option
+ <b>allow_pretty_writing_to_this_dir</b>. So once you have written to the COW
+ library's local directory by doing a footprint save, no github updates will
+ be seen when loading a footprint by the same name as one for which you've
+ written locally.
+
+ <p>Always keep a separate local *.pretty directory for each Github library,
+ never combine them by referring to the same directory more than once. Also,
+ do not also use the same COW (*.pretty) directory in a "KiCad" fp-lib-table
+ entry. This would likely create a mess. The COW directory should be manually
+ created in advance, and the directory name must end with ".pretty". The value
+ of the option <b>allow_pretty_writing_to_this_dir</b> will be path
+ substituted with any environment variable strings embedded, just like the
+ "Library Path" is.
+
+ <p>What's the point of COW? It is to turbo-charge the sharing of footprints.
+ If you periodically email your COW pretty footprint modifications to the
+ Github repo maintainer, you can help update the Github copy. Simply email the
+ individual *.kicad_mod files you find in your COW directories. After you've
+ received confirmation that your changes have been committed up at github.com,
+ you can safely delete your COW file(s) and those from github.com will flow
+ down. Your goal should be to keep the COW file set as small as possible by
+ contributing frequently to the shared master copies at https://github.com.
+
+ <p>Note that if you use the module editor to delete a footprint and it is
+ present in the COW local dir, it will get deleted from there. However, it may
+ not be deleted from the library as a whole if the footprint of the same name
+ also exists in the github repo. In this case deleting the local copy will
+ simply unmask the one at the github repo. Remember, it is masked out if there
+ is a local COW copy, since the local copy always takes precedence. And
+ remember you cannot modify the github copy except by emailing a COW
+ modification to the repo maintainer.
+
+ <p>If you happen to be the repo maintainer, then the obvious solution for you
+ is to make your COW directory <b>be</b> your working copy directory. From
+ there you can push to github. And you can receive *.kicad_mod files by email
+ and put them into your local working copy directory also and do diffs,
+ reverting or denying when appropriate, editing when appropriate before
+ pushing or denying the change. Ultimately you would owe the sender either a
+ note of acceptance or denial by email.
+
+ @author Dick Hollenbeck
+ @date Original date: 10-Sep-2013
+
+ */
+class GITHUB_PLUGIN : public PCB_IO
+{
+public:
+ //-----<PLUGIN API>----------------------------------------------------------
+ const wxString PluginName() const;
+
+ const wxString GetFileExtension() const;
+
+ wxArrayString FootprintEnumerate( const wxString& aLibraryPath,
+ const PROPERTIES* aProperties = NULL );
+
+ MODULE* FootprintLoad( const wxString& aLibraryPath,
+ const wxString& aFootprintName, const PROPERTIES* aProperties );
+
+ void FootprintSave( const wxString& aLibraryPath, const MODULE* aFootprint,
+ const PROPERTIES* aProperties = NULL );
+
+ void FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName,
+ const PROPERTIES* aProperties = NULL );
+
+ bool IsFootprintLibWritable( const wxString& aLibraryPath );
+
+ void FootprintLibOptions( PROPERTIES* aListToAppendTo ) const;
+
+ // Since I derive from PCB_IO, I have to implement this, else I'd inherit his, which is bad since
+ // my lib_path is not his. Note: it is impossible to create a Github library, but can the C.O.W. portion.
+ void FootprintLibCreate( const wxString& aLibraryPath, const PROPERTIES* aProperties );
+
+ // Since I derive from PCB_IO, I have to implement this, else I'd inherit his, which is bad since
+ // my lib_path is not his. Note: it is impossible to delete a Github library, but can the C.O.W portion.
+ bool FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties );
+
+ //-----</PLUGIN API>---------------------------------------------------------
+
+ GITHUB_PLUGIN(); // constructor, if any, must be zero arg
+ ~GITHUB_PLUGIN();
+
+protected:
+
+ void init( const PROPERTIES* aProperties );
+
+ void cacheLib( const wxString& aLibraryPath, const PROPERTIES* aProperties );
+
+ /**
+ * Function repoURL_zipURL
+ * translates a repo URL to a zipfile URL name as commonly seen on github.com
+ *
+ * @param aRepoURL points to the base of the repo.
+ * @param aZipURL is where to put the zip file URL.
+ * @return bool - true if @a aRepoULR was parseable, else false
+ */
+ static bool repoURL_zipURL( const wxString& aRepoURL, std::string* aZipURL );
+
+ /**
+ * Function remoteGetZip
+ * fetches a zip file image from a github repo synchronously. The byte image
+ * is received into the m_input_stream.
+ */
+ void remoteGetZip( const wxString& aRepoURL ) throw( IO_ERROR );
+
+ wxString m_lib_path; ///< from aLibraryPath, something like https://github.com/liftoff-sr/pretty_footprints
+ std::string m_zip_image; ///< byte image of the zip file in its entirety.
+ GH_CACHE* m_gh_cache;
+ wxString m_pretty_dir;
+};
+
+
+#endif // GITHUB_PLUGIN_H_
diff --git a/pcbnew/github/html_link_parser.cpp b/pcbnew/github/html_link_parser.cpp
new file mode 100644
index 0000000..b548b67
--- /dev/null
+++ b/pcbnew/github/html_link_parser.cpp
@@ -0,0 +1,69 @@
+/**
+ * @file html_link_parse.cpp
+ */
+
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/*
+ * wxWidgets gives very few info about wxwebkit. For more info and more comments:
+ * see https://forums.wxwidgets.org/viewtopic.php?f=1&t=1119#
+ */
+
+#include <html_link_parser.h>
+
+bool LINK_TAGHANDLER::HandleTag(const wxHtmlTag& tag)
+{
+ if( tag.HasParam( wxT("HREF") ) )
+ {
+ wxString href( tag.GetParam( wxT("HREF") ) );
+ // Add the first parameter (the link)
+ m_Parser->AddString( href );
+ // Parse other params, but do nothing, because the AddText() callback
+ // do nothing
+ ParseInner(tag);
+ return true;
+ }
+ else
+ return false;
+}
+
+HTML_LINK_PARSER::HTML_LINK_PARSER( const wxString& aSrc, wxArrayString& aUrls )
+ : m_src( aSrc ), stringUrls( aUrls )
+{
+ m_filter = NULL;
+ AddTagHandler( new LINK_TAGHANDLER(this) );
+}
+
+
+void HTML_LINK_PARSER::AddString( const wxString& aText )
+{
+ wxString text = aText;
+ text.Trim( true );
+ text.Trim( false );
+
+ if( ! m_filter || m_filter( text ) )
+ {
+ stringUrls.Add( text );
+ }
+}
diff --git a/pcbnew/github/html_link_parser.h b/pcbnew/github/html_link_parser.h
new file mode 100644
index 0000000..c18c27e
--- /dev/null
+++ b/pcbnew/github/html_link_parser.h
@@ -0,0 +1,109 @@
+/**
+ * @file html_link_parse.h
+ */
+
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 1992-2014 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/*
+ * wxWidgets gives very few info about wxwebkit. For more info and more comments:
+ * see https://forums.wxwidgets.org/viewtopic.php?f=1&t=1119#
+ */
+
+#ifndef HTML_LINK_PARSE_H
+#define HTML_LINK_PARSE_H
+
+
+#include <wx/wx.h>
+#include <wx/html/htmlpars.h>
+
+class HTML_LINK_PARSER ;
+
+/**
+ * a Tag parser, to extract tagged data in html text.
+ * this tag handler extract a url link, givent by tag "A"
+ * like:
+ * "<a href="/KiCad/Valves.pretty" itemprop="name codeRepository"> Valves.pretty</a>"
+ * the tag is "a"
+ * and the link is the parameter given by "href"
+ */
+class LINK_TAGHANDLER : public wxHtmlTagHandler
+{
+ HTML_LINK_PARSER* m_Parser;
+
+public:
+ LINK_TAGHANDLER() : m_Parser( NULL )
+ {
+ }
+
+ LINK_TAGHANDLER( HTML_LINK_PARSER* aParser ) : m_Parser( aParser )
+ {
+ }
+
+ wxString GetSupportedTags()
+ {
+ return "A";
+ }
+
+ bool HandleTag(const wxHtmlTag& tag);
+};
+
+/**
+ * The engine to parse a html text and extract useful data
+ * Here, the useful data are url links
+ */
+class HTML_LINK_PARSER : public wxHtmlParser
+{
+ const wxString& m_src; // the html text to parse
+ wxArrayString& stringUrls; // the strings extracted from html text
+ bool (*m_filter)( const wxString& aData ); // a callback function to filter strings
+
+public:
+
+ HTML_LINK_PARSER( const wxString& aSrc, wxArrayString& aUrls );
+
+ /**
+ * Parse the html text and store links in stringUrls
+ * Stored links can be filtered if aFilter is non NULL
+ * @param aFilter a filtering function ( bool aFilter( const wxString& aData ) )
+ * which return true if the text aData must be stored.
+ */
+ void ParseLinks( bool (*aFilter)( const wxString& aData ) )
+ {
+ m_filter = aFilter;
+ Parse(m_src);
+ }
+
+ // virtual pure from wxHtmlParser, do nothing here, but needed.
+ void AddText( const wxString& aText ){}
+
+ // Our "AddText" used to store selected text (the url link)
+ void AddString( const wxString& aText );
+
+ wxObject* GetProduct()
+ {
+ return NULL;
+ }
+};
+
+#endif // ifndef HTML_LINK_PARSE_H
diff --git a/pcbnew/github/nginx.conf b/pcbnew/github/nginx.conf
new file mode 100644
index 0000000..24f3320
--- /dev/null
+++ b/pcbnew/github/nginx.conf
@@ -0,0 +1,64 @@
+# Author: <Dick Hollenbeck> dick@softplc.com
+# Configuration file for nginx. Nginx works as a nice cache-ing proxy for
+# the github footprint repos in a local nginx instance.
+
+
+# In my case I also added a small RAM disk on a linux server to hold the cache.
+# This line in /etc/fstab adds my RAM disk, this is 10 mbytes but 5mb would
+# probably suffice:
+none /var/cache/nginx tmpfs size=10m
+
+# I then set my KIGITHUB environment variable to
+# export KIGITHUB=http://my_server:54321/KiCad
+
+# Note that http is used between kicad and nginx, not https. However nginx uses
+# https when refreshing from github. http is faster than https.
+
+# You can run nginx either on your local machine, or on a server on your network,
+# or a server on the Internet. In my case I run it on my network. I imagine
+# that even a Raspery Pi would act as a decent caching server so long as you
+# install nginx and give the machine Internet access.
+
+
+worker_processes 2;
+
+events {
+ worker_connections 1024;
+}
+
+
+http {
+ proxy_cache_path /var/cache/nginx keys_zone=cache_zone:10m;
+
+ server {
+ # nginx will listen on this port:
+ listen 54321;
+
+ proxy_cache cache_zone;
+
+ # hold the stuff for one week, then mark it as out of date which will
+ # cause it to be reloaded from github.
+ proxy_cache_valid 1w;
+
+ location /KiCad/ {
+ rewrite /KiCad/(.+) /KiCad/$1/zip/master break;
+
+ # Skip past the redirect issued by https://github.com
+ proxy_pass https://codeload.github.com;
+
+ proxy_set_header Proxy-Connection "Keep-Alive";
+
+ proxy_ignore_headers "Set-Cookie";
+ proxy_ignore_headers "Cache-Control";
+ proxy_ignore_headers "Expires";
+
+ proxy_cache_bypass $http_secret_header;
+
+ add_header X-Cache-Status $upstream_cache_status;
+
+ # This line causes github.com to return a "502 Bad Gateway Error"
+ # so do not include it:
+ # proxy_set_header Host $http_host;
+ }
+ }
+}