← Back to team overview

kicad-developers team mailing list archive

[PATCH] Add remote lib retrieval to SCH_LEGACY_PLUGIN_CACHE

 

Hi,

Here in the attachment the patch that add the remote lib retrieval.

Badr
Le 2017-08-13 17:29, Badr Hack&Invent a écrit :
Hi,

Those couple of days I was checking how to update EESCHEMA to add
remote libraries retrieval function.

Since am familiar with legacy format, I updated the plugin:
SCH_LEGACY_PLUGIN_CACHE in charge of parsing the *.lib files.

The idea was to create a new type of library EESchema-REMOTELIBRARY (I
put an example in the attachment)
The content of this library is the following:
EESchema-REMOTELIBRARY Version 1.0
URL https://www.example.com/mylib1.lib
URL https://www.example.com/mylib2.lib
...

This lib file is saved localy and specify the path of each remote
library you want to retrieve.

The updated code seemlessly check the type of the library, if it is
EESchema-LIBRARY it parse it like always, else if it is
EESchema-REMOTELIBRARY it download each remote lib and parse it when
it is EESchema-LIBRARY (no recusivity with EESchema-REMOTELIBRARY).

The impacted files are:  sch_legacy_plugin.cpp and sch_legacy_plugin.h
-> I implemented the algo and made some tweeks to use LINE_READER
instead of FILE_LINE_READER as argument to manage to use
STRING_LINE_READER

I also modified KICAD_CURL_EASY::KICAD_CURL_EASY() to set the option
CURLOPT_SSL_VERIFYHOST to 0 to disable ssl certificate checking in
https requests. This modification is not required, but was useflul for
our case where our server is behind ssl without certificate on the
domaine, just ip addresses.

I made a prototype in the attachment, it is woring.

I don't know if this modification is inline with the arachitecture of kicad?

Badr
From 896cbc5f18bd8bf3d6a1258fc2b1824188e12b24 Mon Sep 17 00:00:00 2001
From: badr elhassak <belhassa@xxxxxxxxxxxxx>
Date: Sun, 13 Aug 2017 21:13:43 +0200
Subject: [PATCH] Add remote lib retrieval to SCH_LEGACY_PLUGIN_CACHE

---
 common/kicad_curl/kicad_curl_easy.cpp |   2 +
 eeschema/sch_legacy_plugin.cpp        | 217 ++++++++++++++++++++++++++++------
 2 files changed, 180 insertions(+), 39 deletions(-)

diff --git a/common/kicad_curl/kicad_curl_easy.cpp b/common/kicad_curl/kicad_curl_easy.cpp
index 1e84afe..c1d4d24 100644
--- a/common/kicad_curl/kicad_curl_easy.cpp
+++ b/common/kicad_curl/kicad_curl_easy.cpp
@@ -61,6 +61,8 @@ KICAD_CURL_EASY::KICAD_CURL_EASY() :
 
     curl_easy_setopt( m_CURL, CURLOPT_WRITEFUNCTION, write_callback );
     curl_easy_setopt( m_CURL, CURLOPT_WRITEDATA, (void*) &m_buffer );
+    // To be able to connect to a https server regardless the certificate issues
+    curl_easy_setopt( m_CURL, CURLOPT_SSL_VERIFYHOST, 0L);
 }
 
 
diff --git a/eeschema/sch_legacy_plugin.cpp b/eeschema/sch_legacy_plugin.cpp
index 21def36..b0bb9ff 100644
--- a/eeschema/sch_legacy_plugin.cpp
+++ b/eeschema/sch_legacy_plugin.cpp
@@ -20,6 +20,8 @@
  * with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <kicad_curl/kicad_curl_easy.h>     // Include before any wx file
+
 #include <ctype.h>
 #include <algorithm>
 
@@ -140,7 +142,7 @@ static bool strCompare( const char* aString, const char* aLine, const char** aOu
  * @throws An #IO_ERROR on an unexpected end of line.
  * @throws A #PARSE_ERROR if the parsed token is not a valid integer.
  */
-static int parseInt( FILE_LINE_READER& aReader, const char* aLine, const char** aOutput = NULL )
+static int parseInt( LINE_READER& aReader, const char* aLine, const char** aOutput = NULL )
 {
     if( !*aLine )
         SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aLine );
@@ -275,7 +277,7 @@ static double parseDouble( FILE_LINE_READER& aReader, const char* aLine,
  * @throws An #IO_ERROR on an unexpected end of line.
  * @throws A #PARSE_ERROR if the parsed token is not a a single character token.
  */
-static char parseChar( FILE_LINE_READER& aReader, const char* aCurrentToken,
+static char parseChar( LINE_READER& aReader, const char* aCurrentToken,
                        const char** aNextToken = NULL )
 {
     while( *aCurrentToken && isspace( *aCurrentToken ) )
@@ -317,7 +319,7 @@ static char parseChar( FILE_LINE_READER& aReader, const char* aCurrentToken,
  * @throws An #IO_ERROR on an unexpected end of line.
  * @throws A #PARSE_ERROR if the \a aCanBeEmpty is false and no string was parsed.
  */
-static void parseUnquotedString( wxString& aString, FILE_LINE_READER& aReader,
+static void parseUnquotedString( wxString& aString, LINE_READER& aReader,
                                  const char* aCurrentToken, const char** aNextToken = NULL,
                                  bool aCanBeEmpty = false )
 {
@@ -381,7 +383,7 @@ static void parseUnquotedString( wxString& aString, FILE_LINE_READER& aReader,
  * @throws An #IO_ERROR on an unexpected end of line.
  * @throws A #PARSE_ERROR if the \a aCanBeEmpty is false and no string was parsed.
  */
-static void parseQuotedString( wxString& aString, FILE_LINE_READER& aReader,
+static void parseQuotedString( wxString& aString, LINE_READER& aReader,
                                const char* aCurrentToken, const char** aNextToken = NULL,
                                bool aCanBeEmpty = false )
 {
@@ -483,24 +485,24 @@ class SCH_LEGACY_PLUGIN_CACHE
     int             m_versionMinor;
     int             m_libType;      // Is this cache a component or symbol library.
 
-    LIB_PART*       loadPart( FILE_LINE_READER& aReader );
-    void            loadHeader( FILE_LINE_READER& aReader );
-    void            loadAliases( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
-    void            loadField( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
-    void            loadDrawEntries( std::unique_ptr< LIB_PART >& aPart,
-                                     FILE_LINE_READER&            aReader );
+    LIB_PART*       loadPart(LINE_READER &aReader );
+    void            loadHeader(LINE_READER &aReader );
+    void            loadAliases(std::unique_ptr< LIB_PART >& aPart, LINE_READER &aReader );
+    void            loadField(std::unique_ptr< LIB_PART >& aPart, LINE_READER &aReader );
+    void            loadDrawEntries(std::unique_ptr< LIB_PART >& aPart,
+                                     LINE_READER &aReader );
     void            loadFootprintFilters( std::unique_ptr< LIB_PART >& aPart,
-                                          FILE_LINE_READER&            aReader );
+                                          LINE_READER&            aReader );
     void            loadDocs();
-    LIB_ARC*        loadArc( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
-    LIB_CIRCLE*     loadCircle( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
-    LIB_TEXT*       loadText( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
-    LIB_RECTANGLE*  loadRectangle( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
-    LIB_PIN*        loadPin( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
-    LIB_POLYLINE*   loadPolyLine( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
-    LIB_BEZIER*     loadBezier( std::unique_ptr< LIB_PART >& aPart, FILE_LINE_READER& aReader );
-
-    FILL_T          parseFillMode( FILE_LINE_READER& aReader, const char* aLine,
+    LIB_ARC*        loadArc( std::unique_ptr< LIB_PART >& aPart, LINE_READER& aReader );
+    LIB_CIRCLE*     loadCircle( std::unique_ptr< LIB_PART >& aPart, LINE_READER& aReader );
+    LIB_TEXT*       loadText( std::unique_ptr< LIB_PART >& aPart, LINE_READER& aReader );
+    LIB_RECTANGLE*  loadRectangle( std::unique_ptr< LIB_PART >& aPart, LINE_READER& aReader );
+    LIB_PIN*        loadPin( std::unique_ptr< LIB_PART >& aPart, LINE_READER& aReader );
+    LIB_POLYLINE*   loadPolyLine( std::unique_ptr< LIB_PART >& aPart, LINE_READER& aReader );
+    LIB_BEZIER*     loadBezier( std::unique_ptr< LIB_PART >& aPart, LINE_READER& aReader );
+
+    FILL_T          parseFillMode(LINE_READER &aReader, const char* aLine,
                                    const char** aOutput );
     bool            checkForDuplicates( wxString& aAliasName );
     LIB_ALIAS*      removeAlias( LIB_ALIAS* aAlias );
@@ -523,6 +525,7 @@ public:
     void Save( bool aSaveDocFile = true );
 
     void Load();
+    void LoadRemote(wxString aURL);
 
     void AddSymbol( const LIB_PART* aPart );
 
@@ -2148,6 +2151,122 @@ void SCH_LEGACY_PLUGIN_CACHE::AddSymbol( const LIB_PART* aPart )
     ++m_modHash;
 }
 
+void SCH_LEGACY_PLUGIN_CACHE::LoadRemote(wxString aURL){
+
+    KICAD_CURL_EASY kcurl;      // this can THROW_IO_ERROR
+    wxString url = aURL.Trim();
+
+    kcurl.SetURL( url.ToStdString() );
+    kcurl.SetUserAgent( "http://kicad-pcb.org"; );
+    kcurl.SetHeader( "Accept", "application/lib" );
+    kcurl.SetFollowRedirects( true );
+
+    std::string filecontent;
+
+    try
+    {
+        kcurl.Perform();
+        filecontent = kcurl.GetBuffer();
+
+        // check the status
+        if( ( filecontent.compare( 0, 9, "Not Found", 9 ) == 0 ) ||
+            ( filecontent.compare( 0, 14, "404: Not Found", 14 ) == 0 ) )
+        {
+            UTF8 fmt( _( "Cannot download file '%s'.\nThe file does not exist on the server" ) );
+            std::string msg = StrPrintf( fmt.c_str(),(const char*) url.utf8_str() );
+
+            THROW_IO_ERROR( msg );
+        }
+
+    }
+    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 remote file : '%s'\n.\nReason: '%s'" ) );
+
+        std::string msg = StrPrintf( fmt.c_str(),
+                                     errorcmd,
+                                     url.ToStdString().c_str(),
+                                     (const char*) ioe.What().utf8_str()
+                                     );
+
+        THROW_IO_ERROR( msg );
+    }
+
+    STRING_LINE_READER reader(filecontent,url);
+
+    if( !reader.ReadLine() )
+        THROW_IO_ERROR( _( "unexpected end of remote file" ) );
+
+    const char* line = reader.Line();
+
+    if( !strCompare( "EESchema-LIBRARY Version", line, &line ) )
+    {
+        // Old .sym files (which are libraries with only one symbol, used to store and reuse shapes)
+        // EESchema-LIB Version x.x SYMBOL. They are valid files.
+        if( !strCompare( "EESchema-LIB Version", line, &line ) )
+            SCH_PARSE_ERROR( "file is not a valid component or symbol library file", reader, line );
+    }
+
+    m_versionMajor = parseInt( reader, line, &line );
+
+    if( *line != '.' )
+        SCH_PARSE_ERROR( "invalid file version formatting in header", reader, line );
+
+    line++;
+
+    m_versionMinor = parseInt( reader, line, &line );
+
+    if( m_versionMajor < 1 || m_versionMinor < 0 || m_versionMinor > 99 )
+        SCH_PARSE_ERROR( "invalid file version in header", reader, line );
+
+    // Check if this is a symbol library which is the same as a component library but without
+    // any alias, documentation, footprint filters, etc.
+    if( strCompare( "SYMBOL", line, &line ) )
+    {
+        // Symbol files add date and time stamp info to the header.
+        m_libType = LIBRARY_TYPE_SYMBOL;
+
+        /// @todo Probably should check for a valid date and time stamp even though it's not used.
+    }
+    else
+    {
+        m_libType = LIBRARY_TYPE_EESCHEMA;
+    }
+
+    while( reader.ReadLine() )
+    {
+        line = reader.Line();
+
+        if( *line == '#' || isspace( *line ) )  // Skip comments and blank lines.
+            continue;
+
+        // Headers where only supported in older library file formats.
+        if( m_libType == LIBRARY_TYPE_EESCHEMA && strCompare( "$HEADER", line ) )
+            loadHeader( reader );
+
+        if( strCompare( "DEF", line ) )
+        {
+            // Read one DEF/ENDDEF part entry from library:
+            loadPart( reader );
+
+        }
+    }
+
+    ++m_modHash;
+
+    // Remember the file modification time of library file when the
+    // cache snapshot was made, so that in a networked environment we will
+    // reload the cache as needed.
+    m_fileModTime = GetLibModificationTime();
+
+    if( USE_OLD_DOC_FILE_FORMAT( m_versionMajor, m_versionMinor ) )
+        loadDocs();
+
+}
 
 void SCH_LEGACY_PLUGIN_CACHE::Load()
 {
@@ -2165,6 +2284,26 @@ void SCH_LEGACY_PLUGIN_CACHE::Load()
 
     const char* line = reader.Line();
 
+    // Check if the library is a remote file lib - To
+    if( strCompare( "EESchema-REMOTELIBRARY Version", line ) )
+    {
+        while( reader.ReadLine() )
+        {
+            line = reader.Line();
+
+            if( *line == '#' || isspace( *line ) )  // Skip comments and blank lines.
+                continue;
+
+            if( strCompare( "URL", line, &line ) )
+            {
+                // Load from the URL
+                LoadRemote(wxString::FromUTF8(line));
+            }
+        }
+
+        return;
+    }
+
     if( !strCompare( "EESchema-LIBRARY Version", line, &line ) )
     {
         // Old .sym files (which are libraries with only one symbol, used to store and reuse shapes)
@@ -2324,7 +2463,7 @@ void SCH_LEGACY_PLUGIN_CACHE::loadDocs()
 }
 
 
-void SCH_LEGACY_PLUGIN_CACHE::loadHeader( FILE_LINE_READER& aReader )
+void SCH_LEGACY_PLUGIN_CACHE::loadHeader( LINE_READER& aReader )
 {
     const char* line = aReader.Line();
 
@@ -2346,7 +2485,7 @@ void SCH_LEGACY_PLUGIN_CACHE::loadHeader( FILE_LINE_READER& aReader )
 }
 
 
-LIB_PART* SCH_LEGACY_PLUGIN_CACHE::loadPart( FILE_LINE_READER& aReader )
+LIB_PART* SCH_LEGACY_PLUGIN_CACHE::loadPart( LINE_READER& aReader )
 {
     const char* line = aReader.Line();
 
@@ -2519,7 +2658,7 @@ bool SCH_LEGACY_PLUGIN_CACHE::checkForDuplicates( wxString& aAliasName )
 
 
 void SCH_LEGACY_PLUGIN_CACHE::loadAliases( std::unique_ptr< LIB_PART >& aPart,
-                                           FILE_LINE_READER&            aReader )
+                                           LINE_READER&            aReader )
 {
     wxString newAlias;
     const char* line = aReader.Line();
@@ -2542,7 +2681,7 @@ void SCH_LEGACY_PLUGIN_CACHE::loadAliases( std::unique_ptr< LIB_PART >& aPart,
 
 
 void SCH_LEGACY_PLUGIN_CACHE::loadField( std::unique_ptr< LIB_PART >& aPart,
-                                         FILE_LINE_READER&            aReader )
+                                         LINE_READER&            aReader )
 {
     const char* line = aReader.Line();
 
@@ -2688,7 +2827,7 @@ void SCH_LEGACY_PLUGIN_CACHE::loadField( std::unique_ptr< LIB_PART >& aPart,
 
 
 void SCH_LEGACY_PLUGIN_CACHE::loadDrawEntries( std::unique_ptr< LIB_PART >& aPart,
-                                               FILE_LINE_READER&            aReader )
+                                               LINE_READER&            aReader )
 {
     const char* line = aReader.Line();
 
@@ -2748,7 +2887,7 @@ void SCH_LEGACY_PLUGIN_CACHE::loadDrawEntries( std::unique_ptr< LIB_PART >& aPar
 }
 
 
-FILL_T SCH_LEGACY_PLUGIN_CACHE::parseFillMode( FILE_LINE_READER& aReader, const char* aLine,
+FILL_T SCH_LEGACY_PLUGIN_CACHE::parseFillMode( LINE_READER& aReader, const char* aLine,
                                                const char** aOutput )
 {
     FILL_T mode;
@@ -2775,8 +2914,8 @@ FILL_T SCH_LEGACY_PLUGIN_CACHE::parseFillMode( FILE_LINE_READER& aReader, const
 }
 
 
-LIB_ARC* SCH_LEGACY_PLUGIN_CACHE::loadArc( std::unique_ptr< LIB_PART >& aPart,
-                                           FILE_LINE_READER&            aReader )
+LIB_ARC* SCH_LEGACY_PLUGIN_CACHE::loadArc(std::unique_ptr< LIB_PART >& aPart,
+                                           LINE_READER &aReader )
 {
     const char* line = aReader.Line();
 
@@ -2841,8 +2980,8 @@ LIB_ARC* SCH_LEGACY_PLUGIN_CACHE::loadArc( std::unique_ptr< LIB_PART >& aPart,
 }
 
 
-LIB_CIRCLE* SCH_LEGACY_PLUGIN_CACHE::loadCircle( std::unique_ptr< LIB_PART >& aPart,
-                                                 FILE_LINE_READER&            aReader )
+LIB_CIRCLE* SCH_LEGACY_PLUGIN_CACHE::loadCircle(std::unique_ptr< LIB_PART >& aPart,
+                                                 LINE_READER &aReader )
 {
     const char* line = aReader.Line();
 
@@ -2868,8 +3007,8 @@ LIB_CIRCLE* SCH_LEGACY_PLUGIN_CACHE::loadCircle( std::unique_ptr< LIB_PART >& aP
 }
 
 
-LIB_TEXT* SCH_LEGACY_PLUGIN_CACHE::loadText( std::unique_ptr< LIB_PART >& aPart,
-                                             FILE_LINE_READER&            aReader )
+LIB_TEXT* SCH_LEGACY_PLUGIN_CACHE::loadText(std::unique_ptr< LIB_PART >& aPart,
+                                             LINE_READER &aReader )
 {
     const char* line = aReader.Line();
 
@@ -2975,8 +3114,8 @@ LIB_TEXT* SCH_LEGACY_PLUGIN_CACHE::loadText( std::unique_ptr< LIB_PART >& aPart,
 }
 
 
-LIB_RECTANGLE* SCH_LEGACY_PLUGIN_CACHE::loadRectangle( std::unique_ptr< LIB_PART >& aPart,
-                                                       FILE_LINE_READER&            aReader )
+LIB_RECTANGLE* SCH_LEGACY_PLUGIN_CACHE::loadRectangle(std::unique_ptr< LIB_PART >& aPart,
+                                                       LINE_READER &aReader )
 {
     const char* line = aReader.Line();
 
@@ -3008,7 +3147,7 @@ LIB_RECTANGLE* SCH_LEGACY_PLUGIN_CACHE::loadRectangle( std::unique_ptr< LIB_PART
 
 
 LIB_PIN* SCH_LEGACY_PLUGIN_CACHE::loadPin( std::unique_ptr< LIB_PART >& aPart,
-                                           FILE_LINE_READER&            aReader )
+                                           LINE_READER&            aReader )
 {
     const char* line = aReader.Line();
 
@@ -3194,8 +3333,8 @@ LIB_PIN* SCH_LEGACY_PLUGIN_CACHE::loadPin( std::unique_ptr< LIB_PART >& aPart,
 }
 
 
-LIB_POLYLINE* SCH_LEGACY_PLUGIN_CACHE::loadPolyLine( std::unique_ptr< LIB_PART >& aPart,
-                                                     FILE_LINE_READER&            aReader )
+LIB_POLYLINE* SCH_LEGACY_PLUGIN_CACHE::loadPolyLine(std::unique_ptr< LIB_PART >& aPart,
+                                                     LINE_READER &aReader )
 {
     const char* line = aReader.Line();
 
@@ -3225,7 +3364,7 @@ LIB_POLYLINE* SCH_LEGACY_PLUGIN_CACHE::loadPolyLine( std::unique_ptr< LIB_PART >
 
 
 LIB_BEZIER* SCH_LEGACY_PLUGIN_CACHE::loadBezier( std::unique_ptr< LIB_PART >& aPart,
-                                                 FILE_LINE_READER&            aReader )
+                                                 LINE_READER&            aReader )
 {
     const char* line = aReader.Line();
 
@@ -3255,7 +3394,7 @@ LIB_BEZIER* SCH_LEGACY_PLUGIN_CACHE::loadBezier( std::unique_ptr< LIB_PART >& aP
 
 
 void SCH_LEGACY_PLUGIN_CACHE::loadFootprintFilters( std::unique_ptr< LIB_PART >& aPart,
-                                                    FILE_LINE_READER&            aReader )
+                                                    LINE_READER&            aReader )
 {
     const char* line = aReader.Line();
 
-- 
2.7.4


Follow ups

References