diff options
author | saurabhb17 | 2020-02-26 16:00:53 +0530 |
---|---|---|
committer | GitHub | 2020-02-26 16:00:53 +0530 |
commit | 886d9cb772e81d2e5262284bc3082664f084337f (patch) | |
tree | 6acee185a4dc19113fcbf0f9a3d6941085dedaf7 /pcbnew/github | |
parent | 0db48f6533517ecebfd9f0693f89deca28408b76 (diff) | |
parent | aa35045840b78d3f48212db45da59a2e5c69b223 (diff) | |
download | KiCad-eSim-886d9cb772e81d2e5262284bc3082664f084337f.tar.gz KiCad-eSim-886d9cb772e81d2e5262284bc3082664f084337f.tar.bz2 KiCad-eSim-886d9cb772e81d2e5262284bc3082664f084337f.zip |
Merge pull request #1 from saurabhb17/develop
Added main functions
Diffstat (limited to 'pcbnew/github')
-rw-r--r-- | pcbnew/github/CMakeLists.txt | 50 | ||||
-rw-r--r-- | pcbnew/github/avhttp-master.zip | bin | 0 -> 173539 bytes | |||
-rw-r--r-- | pcbnew/github/github_getliblist.cpp | 242 | ||||
-rw-r--r-- | pcbnew/github/github_getliblist.h | 124 | ||||
-rw-r--r-- | pcbnew/github/github_plugin.cpp | 599 | ||||
-rw-r--r-- | pcbnew/github/github_plugin.h | 229 | ||||
-rw-r--r-- | pcbnew/github/html_link_parser.cpp | 69 | ||||
-rw-r--r-- | pcbnew/github/html_link_parser.h | 109 | ||||
-rw-r--r-- | pcbnew/github/nginx.conf | 64 |
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 Binary files differnew file mode 100644 index 0000000..2fa261a --- /dev/null +++ b/pcbnew/github/avhttp-master.zip 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; + } + } +} |