From c5c7d89751de6c8f4269c2602dfc080cfb1912dc Mon Sep 17 00:00:00 2001 From: Joe Wreschnig Date: Sun, 19 Jun 2022 13:03:44 +0200 Subject: [PATCH] Allow using specific revisions in `lib install --git-url` (#1113) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is done by providing the desired revision in the fragment, e.g. `…/Library.git#0.1.0`. When set, this disables the clone depth limit so all remote references will be available. --- arduino/libraries/librariesmanager/install.go | 38 ++++++++++++++++--- .../librariesmanager/install_test.go | 30 +++++++++++---- cli/lib/install.go | 1 + test/test_lib.py | 33 ++++++++++++++++ 4 files changed, 88 insertions(+), 14 deletions(-) diff --git a/arduino/libraries/librariesmanager/install.go b/arduino/libraries/librariesmanager/install.go index 31233062f4b..734ad6f0230 100644 --- a/arduino/libraries/librariesmanager/install.go +++ b/arduino/libraries/librariesmanager/install.go @@ -30,6 +30,7 @@ import ( "github.com/codeclysm/extract/v3" "github.com/sirupsen/logrus" "gopkg.in/src-d/go-git.v4" + "gopkg.in/src-d/go-git.v4/plumbing" ) type alreadyInstalledError struct{} @@ -190,7 +191,7 @@ func (lm *LibrariesManager) InstallGitLib(gitURL string, overwrite bool) error { return fmt.Errorf(tr("User directory not set")) } - libraryName, err := parseGitURL(gitURL) + libraryName, ref, err := parseGitURL(gitURL) if err != nil { logrus. WithError(err). @@ -218,9 +219,13 @@ func (lm *LibrariesManager) InstallGitLib(gitURL string, overwrite bool) error { WithField("git url", gitURL). Trace("Installing library") - _, err = git.PlainClone(installPath.String(), false, &git.CloneOptions{ + depth := 1 + if ref != "" { + depth = 0 + } + repo, err := git.PlainClone(installPath.String(), false, &git.CloneOptions{ URL: gitURL, - Depth: 1, + Depth: depth, Progress: os.Stdout, }) if err != nil { @@ -230,6 +235,25 @@ func (lm *LibrariesManager) InstallGitLib(gitURL string, overwrite bool) error { return err } + if ref != "" { + if h, err := repo.ResolveRevision(ref); err != nil { + logrus. + WithError(err). + Warnf("Resolving revision %s", ref) + return err + } else if w, err := repo.Worktree(); err != nil { + logrus. + WithError(err). + Warn("Finding worktree") + return err + } else if err := w.Checkout(&git.CheckoutOptions{Hash: plumbing.NewHash(h.String())}); err != nil { + logrus. + WithError(err). + Warnf("Checking out %s", h) + return err + } + } + if err := validateLibrary(installPath); err != nil { // Clean up installation directory since this is not a valid library installPath.RemoveAll() @@ -243,8 +267,9 @@ func (lm *LibrariesManager) InstallGitLib(gitURL string, overwrite bool) error { // parseGitURL tries to recover a library name from a git URL. // Returns an error in case the URL is not a valid git URL. -func parseGitURL(gitURL string) (string, error) { +func parseGitURL(gitURL string) (string, plumbing.Revision, error) { var res string + var rev plumbing.Revision if strings.HasPrefix(gitURL, "git@") { // We can't parse these as URLs i := strings.LastIndex(gitURL, "/") @@ -254,10 +279,11 @@ func parseGitURL(gitURL string) (string, error) { } else if parsed, err := url.Parse(gitURL); parsed.String() != "" && err == nil { i := strings.LastIndex(parsed.Path, "/") res = strings.TrimSuffix(parsed.Path[i+1:], ".git") + rev = plumbing.Revision(parsed.Fragment) } else { - return "", fmt.Errorf(tr("invalid git url")) + return "", "", fmt.Errorf(tr("invalid git url")) } - return res, nil + return res, rev, nil } // validateLibrary verifies the dir contains a valid library, meaning it has either diff --git a/arduino/libraries/librariesmanager/install_test.go b/arduino/libraries/librariesmanager/install_test.go index acf0f620561..169680b5502 100644 --- a/arduino/libraries/librariesmanager/install_test.go +++ b/arduino/libraries/librariesmanager/install_test.go @@ -24,43 +24,57 @@ import ( func TestParseGitURL(t *testing.T) { gitURL := "" - libraryName, err := parseGitURL(gitURL) + libraryName, ref, err := parseGitURL(gitURL) require.Equal(t, "", libraryName) + require.EqualValues(t, "", ref) require.Errorf(t, err, "invalid git url") gitURL = "https://github.com/arduino/arduino-lib.git" - libraryName, err = parseGitURL(gitURL) + libraryName, ref, err = parseGitURL(gitURL) require.Equal(t, "arduino-lib", libraryName) + require.EqualValues(t, "", ref) + require.NoError(t, err) + + gitURL = "https://github.com/arduino/arduino-lib.git#0.1.2" + libraryName, ref, err = parseGitURL(gitURL) + require.Equal(t, "arduino-lib", libraryName) + require.EqualValues(t, "0.1.2", ref) require.NoError(t, err) gitURL = "git@github.com:arduino/arduino-lib.git" - libraryName, err = parseGitURL(gitURL) + libraryName, ref, err = parseGitURL(gitURL) require.Equal(t, "arduino-lib", libraryName) + require.EqualValues(t, "", ref) require.NoError(t, err) gitURL = "file:///path/to/arduino-lib" - libraryName, err = parseGitURL(gitURL) + libraryName, ref, err = parseGitURL(gitURL) require.Equal(t, "arduino-lib", libraryName) + require.EqualValues(t, "", ref) require.NoError(t, err) gitURL = "file:///path/to/arduino-lib.git" - libraryName, err = parseGitURL(gitURL) + libraryName, ref, err = parseGitURL(gitURL) require.Equal(t, "arduino-lib", libraryName) + require.EqualValues(t, "", ref) require.NoError(t, err) gitURL = "/path/to/arduino-lib" - libraryName, err = parseGitURL(gitURL) + libraryName, ref, err = parseGitURL(gitURL) require.Equal(t, "arduino-lib", libraryName) + require.EqualValues(t, "", ref) require.NoError(t, err) gitURL = "/path/to/arduino-lib.git" - libraryName, err = parseGitURL(gitURL) + libraryName, ref, err = parseGitURL(gitURL) require.Equal(t, "arduino-lib", libraryName) + require.EqualValues(t, "", ref) require.NoError(t, err) gitURL = "file:///path/to/arduino-lib" - libraryName, err = parseGitURL(gitURL) + libraryName, ref, err = parseGitURL(gitURL) require.Equal(t, "arduino-lib", libraryName) + require.EqualValues(t, "", ref) require.NoError(t, err) } diff --git a/cli/lib/install.go b/cli/lib/install.go index 616a00d2751..c7ccbfbc9cc 100644 --- a/cli/lib/install.go +++ b/cli/lib/install.go @@ -51,6 +51,7 @@ func initInstallCommand() *cobra.Command { " " + os.Args[0] + " lib install AudioZero # " + tr("for the latest version.") + "\n" + " " + os.Args[0] + " lib install AudioZero@1.0.0 # " + tr("for the specific version.") + "\n" + " " + os.Args[0] + " lib install --git-url https://github.com/arduino-libraries/WiFi101.git https://github.com/arduino-libraries/ArduinoBLE.git\n" + + " " + os.Args[0] + " lib install --git-url https://github.com/arduino-libraries/WiFi101.git#0.16.0 # " + tr("for the specific version.") + "\n" + " " + os.Args[0] + " lib install --zip-path /path/to/WiFi101.zip /path/to/ArduinoBLE.zip\n", Args: cobra.MinimumNArgs(1), Run: runInstallCommand, diff --git a/test/test_lib.py b/test/test_lib.py index 22dac17fec4..6353c7f657f 100644 --- a/test/test_lib.py +++ b/test/test_lib.py @@ -348,6 +348,39 @@ def test_install_with_git_url(run_command, data_dir, downloads_dir): assert lib_install_dir.exists() +def test_install_with_git_url_fragment_as_branch(run_command, data_dir, downloads_dir): + # Initialize configs to enable --git-url flag + env = { + "ARDUINO_DATA_DIR": data_dir, + "ARDUINO_DOWNLOADS_DIR": downloads_dir, + "ARDUINO_SKETCHBOOK_DIR": data_dir, + "ARDUINO_ENABLE_UNSAFE_LIBRARY_INSTALL": "true", + } + assert run_command(["config", "init", "--dest-dir", "."], custom_env=env) + + lib_install_dir = Path(data_dir, "libraries", "WiFi101") + # Verifies library is not already installed + assert not lib_install_dir.exists() + + git_url = "https://github.com/arduino-libraries/WiFi101.git" + + # Test that a bad ref fails + res = run_command(["lib", "install", "--git-url", git_url + "#x-ref-does-not-exist"]) + assert res.failed + + # Verifies library is installed in expected path + res = run_command(["lib", "install", "--git-url", git_url + "#0.16.0"]) + assert res.ok + assert lib_install_dir.exists() + + # Reinstall library at an existing ref + assert run_command(["lib", "install", "--git-url", git_url + "#master"]) + assert res.ok + + # Verifies library remains installed + assert lib_install_dir.exists() + + def test_install_with_zip_path(run_command, data_dir, downloads_dir): # Initialize configs to enable --zip-path flag env = {