| 
									
										
										
										
											2017-04-07 02:28:09 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2018-08-25 03:03:55 +08:00
										 |  |  | Copyright The Helm Authors. | 
					
						
							| 
									
										
										
										
											2017-04-07 02:28:09 +08:00
										 |  |  | Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  | you may not use this file except in compliance with the License. | 
					
						
							|  |  |  | You may obtain a copy of the License at | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  | distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  | See the License for the specific language governing permissions and | 
					
						
							|  |  |  | limitations under the License. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-17 05:42:00 +08:00
										 |  |  | package installer // import "helm.sh/helm/v4/internal/plugin/installer"
 | 
					
						
							| 
									
										
										
										
											2017-04-07 02:28:09 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2025-08-21 16:40:16 +08:00
										 |  |  | 	"archive/tar" | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							|  |  |  | 	"compress/gzip" | 
					
						
							| 
									
										
										
										
											2017-04-07 02:28:09 +08:00
										 |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-04 08:40:05 +08:00
										 |  |  | 	"helm.sh/helm/v4/internal/test/ensure" | 
					
						
							| 
									
										
										
										
											2024-12-27 05:33:51 +08:00
										 |  |  | 	"helm.sh/helm/v4/pkg/helmpath" | 
					
						
							| 
									
										
										
										
											2017-04-07 02:28:09 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var _ Installer = new(LocalInstaller) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestLocalInstaller(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2025-06-04 08:40:05 +08:00
										 |  |  | 	ensure.HelmHome(t) | 
					
						
							| 
									
										
										
										
											2017-04-07 02:28:09 +08:00
										 |  |  | 	// Make a temp dir
 | 
					
						
							| 
									
										
										
										
											2022-02-12 13:54:54 +08:00
										 |  |  | 	tdir := t.TempDir() | 
					
						
							| 
									
										
										
										
											2023-03-22 21:31:16 +08:00
										 |  |  | 	if err := os.WriteFile(filepath.Join(tdir, "plugin.yaml"), []byte{}, 0644); err != nil { | 
					
						
							| 
									
										
										
										
											2017-04-07 02:28:09 +08:00
										 |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-18 06:18:05 +08:00
										 |  |  | 	source := "../testdata/plugdir/good/echo-v1" | 
					
						
							| 
									
										
										
										
											2019-01-14 16:11:21 +08:00
										 |  |  | 	i, err := NewForSource(source, "") | 
					
						
							| 
									
										
										
										
											2017-04-07 02:28:09 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-04-23 06:33:01 +08:00
										 |  |  | 		t.Fatalf("unexpected error: %s", err) | 
					
						
							| 
									
										
										
										
											2017-04-07 02:28:09 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := Install(i); err != nil { | 
					
						
							| 
									
										
										
										
											2019-08-27 01:21:52 +08:00
										 |  |  | 		t.Fatal(err) | 
					
						
							| 
									
										
										
										
											2017-04-07 02:28:09 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-18 06:18:05 +08:00
										 |  |  | 	if i.Path() != helmpath.DataPath("plugins", "echo-v1") { | 
					
						
							| 
									
										
										
										
											2020-04-23 06:33:01 +08:00
										 |  |  | 		t.Fatalf("expected path '$XDG_CONFIG_HOME/helm/plugins/helm-env', got %q", i.Path()) | 
					
						
							| 
									
										
										
										
											2017-04-07 02:28:09 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-11-23 15:39:14 +08:00
										 |  |  | 	defer os.RemoveAll(filepath.Dir(helmpath.DataPath())) // helmpath.DataPath is like /tmp/helm013130971/helm
 | 
					
						
							| 
									
										
										
										
											2017-04-07 02:28:09 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-11-04 22:48:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestLocalInstallerNotAFolder(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2025-08-18 06:18:05 +08:00
										 |  |  | 	source := "../testdata/plugdir/good/echo-v1/plugin.yaml" | 
					
						
							| 
									
										
										
										
											2022-11-04 22:48:48 +08:00
										 |  |  | 	i, err := NewForSource(source, "") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("unexpected error: %s", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = Install(i) | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		t.Fatal("expected error") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err != ErrPluginNotAFolder { | 
					
						
							|  |  |  | 		t.Fatalf("expected error to equal: %q", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-08-21 16:40:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestLocalInstallerTarball(t *testing.T) { | 
					
						
							|  |  |  | 	ensure.HelmHome(t) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create a test tarball
 | 
					
						
							|  |  |  | 	tempDir := t.TempDir() | 
					
						
							|  |  |  | 	tarballPath := filepath.Join(tempDir, "test-plugin-1.0.0.tar.gz") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create tarball content
 | 
					
						
							|  |  |  | 	var buf bytes.Buffer | 
					
						
							|  |  |  | 	gw := gzip.NewWriter(&buf) | 
					
						
							|  |  |  | 	tw := tar.NewWriter(gw) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	files := []struct { | 
					
						
							|  |  |  | 		Name string | 
					
						
							|  |  |  | 		Body string | 
					
						
							|  |  |  | 		Mode int64 | 
					
						
							|  |  |  | 	}{ | 
					
						
							| 
									
										
										
										
											2025-08-31 01:25:28 +08:00
										 |  |  | 		{"test-plugin/plugin.yaml", "name: test-plugin\nversion: 1.0.0\nusage: test\ndescription: test\ncommand: echo", 0644}, | 
					
						
							|  |  |  | 		{"test-plugin/bin/test-plugin", "#!/bin/bash\necho test", 0755}, | 
					
						
							| 
									
										
										
										
											2025-08-21 16:40:16 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, file := range files { | 
					
						
							|  |  |  | 		hdr := &tar.Header{ | 
					
						
							|  |  |  | 			Name: file.Name, | 
					
						
							|  |  |  | 			Mode: file.Mode, | 
					
						
							|  |  |  | 			Size: int64(len(file.Body)), | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err := tw.WriteHeader(hdr); err != nil { | 
					
						
							|  |  |  | 			t.Fatal(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if _, err := tw.Write([]byte(file.Body)); err != nil { | 
					
						
							|  |  |  | 			t.Fatal(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := tw.Close(); err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := gw.Close(); err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Write tarball to file
 | 
					
						
							|  |  |  | 	if err := os.WriteFile(tarballPath, buf.Bytes(), 0644); err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Test installation
 | 
					
						
							|  |  |  | 	i, err := NewForSource(tarballPath, "") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("unexpected error: %s", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Verify it's detected as LocalInstaller
 | 
					
						
							|  |  |  | 	localInstaller, ok := i.(*LocalInstaller) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		t.Fatal("expected LocalInstaller") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if !localInstaller.isArchive { | 
					
						
							|  |  |  | 		t.Fatal("expected isArchive to be true") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := Install(i); err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	expectedPath := helmpath.DataPath("plugins", "test-plugin") | 
					
						
							|  |  |  | 	if i.Path() != expectedPath { | 
					
						
							|  |  |  | 		t.Fatalf("expected path %q, got %q", expectedPath, i.Path()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Verify plugin was installed
 | 
					
						
							|  |  |  | 	if _, err := os.Stat(i.Path()); err != nil { | 
					
						
							|  |  |  | 		t.Fatalf("plugin not found at %s: %v", i.Path(), err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |