@@ -4,12 +4,12 @@ import (
44 "errors"
55 "fmt"
66 "os"
7- "os/exec"
87 "path/filepath"
98 "strings"
109
1110 "github.com/bitrise-io/bitrise/v2/log"
1211 "github.com/bitrise-io/bitrise/v2/toolprovider/mise/execenv"
12+ "github.com/bitrise-io/bitrise/v2/toolprovider/mise/nixpkgs"
1313 "github.com/bitrise-io/bitrise/v2/toolprovider/provider"
1414)
1515
@@ -41,11 +41,6 @@ var miseStableChecksums = map[string]string{
4141 "macos-arm64" : "0b5893de7c8c274736867b7c4c7ed565b4429f4d6272521ace802f8a21422319" ,
4242}
4343
44- const (
45- nixpkgsPluginGitURL = "https://github.com/bitrise-io/mise-nixpkgs-plugin.git"
46- nixpkgsPluginName = "mise-nixpkgs-plugin"
47- )
48-
4944type MiseToolProvider struct {
5045 ExecEnv execenv.ExecEnv
5146}
@@ -108,49 +103,60 @@ func (m *MiseToolProvider) Bootstrap() error {
108103}
109104
110105func (m * MiseToolProvider ) InstallTool (tool provider.ToolRequest ) (provider.ToolInstallResult , error ) {
111- useNix := m .shouldUseNixPkgs (tool )
106+ useNix , err := m .ShouldInstallWithNix (tool )
107+ if err != nil {
108+ return provider.ToolInstallResult {}, err
109+ }
112110
113- if useNix {
114- tool .ToolName = provider .ToolID (fmt .Sprintf ("nixpkgs:%s" , tool .ToolName ))
115- } else {
116- err := m .InstallPlugin (tool )
111+ if ! useNix {
112+ err = m .InstallPlugin (tool )
117113 if err != nil {
118114 return provider.ToolInstallResult {}, fmt .Errorf ("install tool plugin %s: %w" , tool .ToolName , err )
119115 }
120116 }
121117
122- isAlreadyInstalled , err := isAlreadyInstalled (tool , m .resolveToLatestInstalled )
118+ var installRequest provider.ToolRequest
119+ if useNix {
120+ installRequest = provider.ToolRequest {
121+ // Use Mise's backend plugin convention of pluginID:toolID
122+ ToolName : provider .ToolID (fmt .Sprintf ("nixpkgs:%s" , tool .ToolName )),
123+ UnparsedVersion : tool .UnparsedVersion ,
124+ ResolutionStrategy : tool .ResolutionStrategy ,
125+ PluginURL : nil , // Not relevant when using nixpkgs backend plugin
126+ }
127+ } else {
128+ installRequest = tool
129+ }
130+
131+ isAlreadyInstalled , err := isAlreadyInstalled (installRequest , m .resolveToLatestInstalled )
123132 if err != nil {
124133 return provider.ToolInstallResult {}, err
125134 }
126135
127- if ! useNix {
128- // Nix already checks version existence previously
129- versionExists , err := m .versionExists (tool .ToolName , tool .UnparsedVersion )
130- if err != nil {
131- return provider.ToolInstallResult {}, fmt .Errorf ("check if version exists: %w" , err )
132- }
133- if ! versionExists {
134- return provider.ToolInstallResult {}, provider.ToolInstallError {
135- ToolName : tool .ToolName ,
136- RequestedVersion : tool .UnparsedVersion ,
137- Cause : fmt .Sprintf ("no match for requested version %s" , tool .UnparsedVersion ),
138- }
136+ versionExists , err := m .versionExists (tool .ToolName , tool .UnparsedVersion )
137+ if err != nil {
138+ return provider.ToolInstallResult {}, fmt .Errorf ("check if version exists: %w" , err )
139+ }
140+ if ! versionExists {
141+ return provider.ToolInstallResult {}, provider.ToolInstallError {
142+ ToolName : tool .ToolName ,
143+ RequestedVersion : tool .UnparsedVersion ,
144+ Cause : fmt .Sprintf ("no match for requested version %s" , tool .UnparsedVersion ),
139145 }
140146 }
141147
142- err = m .installToolVersion (tool )
148+ err = m .installToolVersion (installRequest )
143149 if err != nil {
144150 return provider.ToolInstallResult {}, err
145151 }
146152
147- concreteVersion , err := m .resolveToConcreteVersionAfterInstall (tool )
153+ concreteVersion , err := m .resolveToConcreteVersionAfterInstall (installRequest )
148154 if err != nil {
149155 return provider.ToolInstallResult {}, fmt .Errorf ("resolve exact version after install: %w" , err )
150156 }
151157
152158 return provider.ToolInstallResult {
153- ToolName : tool .ToolName ,
159+ ToolName : installRequest .ToolName ,
154160 IsAlreadyInstalled : isAlreadyInstalled ,
155161 ConcreteVersion : concreteVersion ,
156162 }, nil
@@ -195,111 +201,27 @@ func GetMiseChecksums() map[string]string {
195201 return miseStableChecksums
196202}
197203
198- func useNixPkgs (tool provider.ToolRequest ) bool {
199- // Note: Add other tools here if needed
200- if tool .ToolName != "ruby" {
201- log .Debugf ("[TOOLPROVIDER] Nix packages are only supported for ruby tool, current tool: %s" , tool .ToolName )
202- return false
203- }
204-
205- if value , variablePresent := os .LookupEnv ("BITRISEIO_MISE_LEGACY_INSTALL" ); variablePresent && strings .Contains (value , "1" ) {
206- log .Debugf ("[TOOLPROVIDER] Using legacy install (non-nix) for tool: %s" , tool .ToolName )
207- return false
204+ func (m * MiseToolProvider ) ShouldInstallWithNix (tool provider.ToolRequest ) (bool , error ) {
205+ if ! nixpkgs .ShouldUseBackend (tool ) {
206+ return false , nil
208207 }
209208
210- return true
211- }
212-
213- // shouldUseNixPkgs checks if Nix packages should be used for the tool installation.
214- // It validates that the tool is eligible for Nix, the plugin is available, and the version exists in the index.
215- // Returns false and logs a warning if any validation fails, falling back to legacy installation.
216- func (m * MiseToolProvider ) shouldUseNixPkgs (tool provider.ToolRequest ) bool {
217- if ! useNixPkgs (tool ) {
218- return false
219- }
220-
221- if err := m .getNixpkgsPlugin (); err != nil {
222- log .Warnf ("Failed to link nixpkgs plugin: %v. Falling back to legacy installation." , err )
223- return false
209+ output , err := m .ExecEnv .RunMisePlugin ("install" , nixpkgs .PluginName , nixpkgs .PluginGitURL )
210+ if err != nil {
211+ return false , fmt .Errorf ("install %s: %s" , nixpkgs .PluginGitURL , output )
224212 }
225213
226214 nameWithBackend := provider .ToolID (fmt .Sprintf ("nixpkgs:%s" , tool .ToolName ))
227215
228216 available , err := m .versionExists (nameWithBackend , tool .UnparsedVersion )
229- if err != nil || ! available {
230- log .Warnf ("Failed to check nixpkgs index for %s@%s: %v. Falling back to legacy installation." , tool .ToolName , tool .UnparsedVersion , err )
231- return false
232- }
233-
234- return true
235- }
236-
237- // findPluginPath finds the nixpkgs plugin directory relative to the bitrise executable.
238- // It first checks next to the binary, then tries a dev location one directory up.
239- // Returns the path if found, otherwise returns an error.
240- func findPluginPath () (string , error ) {
241- execPath , err := os .Executable ()
242- if err != nil {
243- return "" , fmt .Errorf ("get executable path: %w" , err )
244- }
245-
246- execDir := filepath .Dir (execPath )
247- pluginPath := filepath .Join (execDir , nixpkgsPluginName )
248-
249- // Check if the plugin exists besides the binary
250- if _ , err := os .Stat (pluginPath ); os .IsNotExist (err ) {
251- // Try dev location
252- pluginPath = filepath .Join (execDir , ".." , nixpkgsPluginName )
253- if _ , err := os .Stat (pluginPath ); os .IsNotExist (err ) {
254- return "" , fmt .Errorf ("%s not found" , nixpkgsPluginName )
255- }
256- }
257-
258- return pluginPath , nil
259- }
260-
261- // getNixpkgsPlugin clones or updates the nixpkgs backend plugin and links it to mise.
262- // If the plugin directory doesn't exist, it clones from the git URL.
263- // If it exists, it checks out the specified commit/branch.
264- func (m * MiseToolProvider ) getNixpkgsPlugin () error {
265- pluginPath , err := findPluginPath ()
266- needsClone := false
267- if err != nil {
268- // Plugin doesn't exist, we need to clone it
269- needsClone = true
270- execPath , execErr := os .Executable ()
271- if execErr != nil {
272- return fmt .Errorf ("get executable path: %w" , execErr )
273- }
274- pluginPath = filepath .Join (filepath .Dir (execPath ), nixpkgsPluginName )
275- }
276-
277- if needsClone {
278- if err := cloneGitRepo (nixpkgsPluginGitURL , pluginPath ); err != nil {
279- return fmt .Errorf ("clone nixpkgs plugin: %w" , err )
280- }
281- }
282-
283- // Link the plugin using mise plugin link
284- _ , err = m .ExecEnv .RunMisePlugin ("link" , "--force" , "nixpkgs" , pluginPath )
285217 if err != nil {
286- return fmt .Errorf ("link nixpkgs plugin: %w" , err )
218+ log .Warnf ("Error while checking nixpkgs index for %s@%s: %v. Falling back to core plugin installation." , tool .ToolName , tool .UnparsedVersion , err )
219+ return false , nil
287220 }
288-
289- // Enable experimental settings for custom backend
290- if _ , err := m .ExecEnv .RunMise ("settings" , "experimental=true" ); err != nil {
291- return fmt .Errorf ("enable experimental settings: %w" , err )
221+ if ! available {
222+ log .Warnf ("%s@%s not found in nixpkgs index, doing a source build. This may take some time..." , tool .ToolName , tool .UnparsedVersion )
223+ return false , nil
292224 }
293225
294- return nil
295- }
296-
297- // cloneGitRepo clones a git repository to the specified path with minimal history.
298- func cloneGitRepo (repoURL , destPath string ) error {
299- cmd := exec .Command ("git" , "clone" , "--depth" , "1" , "--no-tags" , repoURL , destPath )
300- output , err := cmd .CombinedOutput ()
301- if err != nil {
302- return fmt .Errorf ("git clone failed: %w: %s" , err , string (output ))
303- }
304- return nil
226+ return true , nil
305227}
0 commit comments