A helper class for parsing Salt Grain URLs into protocol, branch, subfolder

This commit is contained in:
Matthias Koefferlein 2023-10-29 15:30:08 +01:00
parent 2ed44e27ad
commit bd785279ef
5 changed files with 390 additions and 0 deletions

View File

@ -33,6 +33,7 @@ HEADERS = \
layResourceHelpProvider.h \
layRuntimeErrorForm.h \
layReaderErrorForm.h \
laySaltParsedURL.h \
laySearchReplaceConfigPage.h \
laySearchReplaceDialog.h \
laySearchReplacePropertiesWidgets.h \
@ -144,6 +145,7 @@ SOURCES = \
layResourceHelpProvider.cc \
layRuntimeErrorForm.cc \
layReaderErrorForm.cc \
laySaltParsedURL.cc \
laySearchReplaceConfigPage.cc \
laySearchReplaceDialog.cc \
laySearchReplacePlugin.cc \

View File

@ -0,0 +1,149 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2023 Matthias Koefferlein
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, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "laySaltParsedURL.h"
#include "laySaltGrain.h"
#include "tlString.h"
namespace lay
{
static void
parse_git_url (tl::Extractor &ex, std::string &url, std::string &branch, std::string &subfolder)
{
const char *org_str = ex.get ();
std::string w;
// protocol (http:)
ex.try_read_word (w, "") && ex.test (":");
while (! ex.at_end () && ex.test ("/")) {
;
}
// server ("www.klayout.de")
while (! ex.at_end () && (*ex != '/' && *ex != '+')) {
++ex;
}
while (! ex.at_end ()) {
++ex;
const char *c1 = ex.get ();
while (! ex.at_end () && (*ex != '/' && *ex != '+' && *ex != '[')) {
++ex;
}
const char *c2 = ex.get ();
std::string comp (c1, c2 - c1);
if ((! ex.at_end () && *ex == '+') || comp.find (".git") == comp.size () - 4) {
// subfolder starts here
break;
}
}
url = std::string (org_str, ex.get () - org_str);
if (ex.at_end ()) {
return;
}
if (*ex == '/') {
while (! ex.at_end () && *ex == '/') {
++ex;
}
} else if (*ex == '+') {
++ex;
}
{
const char *c1 = ex.get ();
while (! ex.at_end () && *ex != '[') {
++ex;
}
const char *c2 = ex.get ();
subfolder = std::string (c1, c2 - c1);
}
if (! ex.at_end () && *ex == '[') {
// explicit branch
++ex;
const char *c1 = ex.get ();
while (! ex.at_end () && *ex != ']') {
++ex;
}
const char *c2 = ex.get ();
branch = std::string (c1, c2 - c1);
} else if (! subfolder.empty ()) {
// SVN emulation
auto parts = tl::split (subfolder, "/");
if (parts.size () >= 1 && parts.back () == "trunk") {
branch = "HEAD";
parts.pop_back ();
subfolder = tl::join (parts, "/");
} else if (parts.size () >= 2 && parts[parts.size () - 2] == "tags") {
branch = "refs/tags/" + parts.back ();
parts.pop_back ();
parts.pop_back ();
subfolder = tl::join (parts, "/");
} else if (parts.size () >= 2 && parts[parts.size () - 2] == "branches") {
branch = "refs/heads/" + parts.back ();
parts.pop_back ();
parts.pop_back ();
subfolder = tl::join (parts, "/");
}
}
}
SaltParsedURL::SaltParsedURL (const std::string &url)
: m_protocol (lay::DefaultProtocol)
{
tl::Extractor ex (url.c_str ());
if (ex.test ("svn") && ex.test ("+")) {
m_protocol = lay::WebDAV;
m_url = ex.get ();
return;
}
ex = tl::Extractor (url.c_str ());
if (ex.test ("git") && ex.test ("+")) {
m_protocol = lay::Git;
parse_git_url (ex, m_url, m_branch, m_subfolder);
return;
}
m_url = url;
}
}

View File

@ -0,0 +1,106 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2023 Matthias Koefferlein
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, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef HDR_laySaltParsedURL
#define HDR_laySaltParsedURL
#include "layCommon.h"
#include "laySaltGrain.h"
namespace lay
{
/**
* @brief A class representing a SaltGrain URL
*
* The URL is parsed into protocol, branch, URL and subfolder if applicable.
* Some heuristics is applied to decompose parts.
*
* SVN URLs:
* https://server.com/repo/trunk -> protocol=DefaultProtocol, url="https://server.com/repo/trunk", branch="", subfolder=""
* svn+https://server.com/repo/trunk -> protocol=WebDAV, url="https://server.com/repo/trunk", branch="", subfolder=""
*
* Git URL heuristics:
* git+https://server.com/repo.git -> protocol=Git, url="https://server.com/repo.git", branch="", subfolder=""
* git+https://server.com/repo.git/sub/folder -> protocol=Git, url="https://server.com/repo.git", branch="", subfolder="sub/folder"
* git+https://server.com/repo+sub/folder -> protocol=Git, url="https://server.com/repo", branch="", subfolder="sub/folder"
* git+https://server.com/repo.git[v1.0] -> protocol=Git, url="https://server.com/repo.git", branch="v1.0", subfolder=""
* git+https://server.com/repo.git/sub/folder[refs/tags/1.0] -> protocol=Git, url="https://server.com/repo.git", branch="refs/tags/1.0", subfolder="sub/folder"
* git+https://server.com/repo.git/trunk -> protocol=Git, url="https://server.com/repo.git", branch="HEAD", subfolder=""
* git+https://server.com/repo.git/sub/folder/trunk -> protocol=Git, url="https://server.com/repo.git", branch="HEAD", subfolder="sub/folder"
* git+https://server.com/repo.git/branches/release -> protocol=Git, url="https://server.com/repo.git", branch="refs/heads/release", subfolder=""
* git+https://server.com/repo.git/tags/1.9 -> protocol=Git, url="https://server.com/repo.git", branch="refs/tags/1.9", subfolder=""
* git+https://server.com/repo.git/sub/folder/tags/1.9 -> protocol=Git, url="https://server.com/repo.git", branch="refs/tags/1.9", subfolder="sub/folder"
*/
class LAY_PUBLIC SaltParsedURL
{
public:
/**
* @brief Constructor: creates an URL from the given generic URL string
*
* This will decompose the URL into the parts and fill protocol, branch and subfolder fields.
*/
SaltParsedURL (const std::string &url);
/**
* @brief Gets the basic URL
*/
const std::string &url () const
{
return m_url;
}
/**
* @brief Gets the subfolder string
*/
const std::string &subfolder () const
{
return m_subfolder;
}
/**
* @brief Gets the branch string
*/
const std::string &branch () const
{
return m_branch;
}
/**
* @brief Gets the protocol
*/
lay::Protocol protocol () const
{
return m_protocol;
}
private:
std::string m_url;
std::string m_branch;
std::string m_subfolder;
lay::Protocol m_protocol;
};
}
#endif

View File

@ -0,0 +1,132 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2023 Matthias Koefferlein
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, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "laySaltParsedURL.h"
#include "tlUnitTest.h"
TEST (1_Basic)
{
lay::SaltParsedURL purl ("https://server.com/repo/trunk");
EXPECT_EQ (purl.protocol () == lay::DefaultProtocol, true);
EXPECT_EQ (purl.url (), "https://server.com/repo/trunk");
EXPECT_EQ (purl.branch (), "");
EXPECT_EQ (purl.subfolder (), "");
}
TEST (2_SVN)
{
lay::SaltParsedURL purl ("svn+https://server.com/repo/trunk");
EXPECT_EQ (purl.protocol () == lay::WebDAV, true);
EXPECT_EQ (purl.url (), "https://server.com/repo/trunk");
EXPECT_EQ (purl.branch (), "");
EXPECT_EQ (purl.subfolder (), "");
}
TEST (10_GitBasic)
{
lay::SaltParsedURL purl ("git+https://server.com/repo.git");
EXPECT_EQ (purl.protocol () == lay::Git, true);
EXPECT_EQ (purl.url (), "https://server.com/repo.git");
EXPECT_EQ (purl.branch (), "");
EXPECT_EQ (purl.subfolder (), "");
}
TEST (11_GitSubFolder)
{
lay::SaltParsedURL purl ("git+https://server.com/repo.git/sub/folder");
EXPECT_EQ (purl.protocol () == lay::Git, true);
EXPECT_EQ (purl.url (), "https://server.com/repo.git");
EXPECT_EQ (purl.branch (), "");
EXPECT_EQ (purl.subfolder (), "sub/folder");
}
TEST (12_GitExplicitBranch)
{
lay::SaltParsedURL purl ("git+https://server.com/repo.git[v1.0]");
EXPECT_EQ (purl.protocol () == lay::Git, true);
EXPECT_EQ (purl.url (), "https://server.com/repo.git");
EXPECT_EQ (purl.branch (), "v1.0");
EXPECT_EQ (purl.subfolder (), "");
}
TEST (13_GitExplicitBranchAndSubFolder)
{
lay::SaltParsedURL purl ("git+https://server.com/repo.git/sub/folder[refs/tags/1.0]");
EXPECT_EQ (purl.protocol () == lay::Git, true);
EXPECT_EQ (purl.url (), "https://server.com/repo.git");
EXPECT_EQ (purl.branch (), "refs/tags/1.0");
EXPECT_EQ (purl.subfolder (), "sub/folder");
}
TEST (14_GitExplicitBranchAndExplicitSubFolder)
{
lay::SaltParsedURL purl ("git+https://server.com/repo+sub/folder[refs/tags/1.0]");
EXPECT_EQ (purl.protocol () == lay::Git, true);
EXPECT_EQ (purl.url (), "https://server.com/repo");
EXPECT_EQ (purl.branch (), "refs/tags/1.0");
EXPECT_EQ (purl.subfolder (), "sub/folder");
}
TEST (15_GitSVNEmulationTrunk)
{
lay::SaltParsedURL purl ("git+https://server.com/repo.git/trunk");
EXPECT_EQ (purl.protocol () == lay::Git, true);
EXPECT_EQ (purl.url (), "https://server.com/repo.git");
EXPECT_EQ (purl.branch (), "HEAD");
EXPECT_EQ (purl.subfolder (), "");
}
TEST (16_GitSVNEmulationTrunkWithSubFolder)
{
lay::SaltParsedURL purl ("git+https://server.com/repo.git/sub/folder/trunk");
EXPECT_EQ (purl.protocol () == lay::Git, true);
EXPECT_EQ (purl.url (), "https://server.com/repo.git");
EXPECT_EQ (purl.branch (), "HEAD");
EXPECT_EQ (purl.subfolder (), "sub/folder");
}
TEST (17_GitSVNEmulationBranch)
{
lay::SaltParsedURL purl ("git+https://server.com/repo.git/branches/xyz");
EXPECT_EQ (purl.protocol () == lay::Git, true);
EXPECT_EQ (purl.url (), "https://server.com/repo.git");
EXPECT_EQ (purl.branch (), "refs/heads/xyz");
EXPECT_EQ (purl.subfolder (), "");
}
TEST (18_GitSVNEmulationTag)
{
lay::SaltParsedURL purl ("git+https://server.com/repo.git/tags/1.9");
EXPECT_EQ (purl.protocol () == lay::Git, true);
EXPECT_EQ (purl.url (), "https://server.com/repo.git");
EXPECT_EQ (purl.branch (), "refs/tags/1.9");
EXPECT_EQ (purl.subfolder (), "");
}
TEST (19_GitSVNEmulationTagWithSubFolder)
{
lay::SaltParsedURL purl ("git+https://server.com/repo.git/sub/folder/tags/1.9");
EXPECT_EQ (purl.protocol () == lay::Git, true);
EXPECT_EQ (purl.url (), "https://server.com/repo.git");
EXPECT_EQ (purl.branch (), "refs/tags/1.9");
EXPECT_EQ (purl.subfolder (), "sub/folder");
}

View File

@ -9,6 +9,7 @@ include($$PWD/../../lib_ut.pri)
SOURCES = \
laySalt.cc \
layHelpIndexTest.cc \
laySaltParsedURLTests.cc \
laySessionTests.cc
INCLUDEPATH += $$LAY_INC $$TL_INC $$LAYBASIC_INC $$LAYUI_INC $$LAYVIEW_INC $$DB_INC $$GSI_INC $$ANT_INC $$IMG_INC $$RDB_INC