File: project.go

package info (click to toggle)
vagrant 2.3.7%2Bgit20230731.5fc64cde%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 17,616 kB
  • sloc: ruby: 111,820; sh: 462; makefile: 123; ansic: 34; lisp: 1
file content (138 lines) | stat: -rw-r--r-- 3,199 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package client

import (
	"context"
	"fmt"
	"os"

	"github.com/hashicorp/go-hclog"

	"github.com/hashicorp/vagrant-plugin-sdk/helper/path"
	vagrant_plugin_sdk "github.com/hashicorp/vagrant-plugin-sdk/proto/vagrant_plugin_sdk"
	"github.com/hashicorp/vagrant-plugin-sdk/terminal"
	"github.com/hashicorp/vagrant/internal/server/proto/vagrant_server"
	"github.com/hashicorp/vagrant/internal/serverclient"
)

// Project is the primary structure for interacting with a Vagrant
// server as a client. The client exposes a slightly higher level of
// abstraction over the server API for performing operations locally and
// remotely.
type Project struct {
	basis       *Basis
	client      *Client
	ctx         context.Context
	logger      hclog.Logger
	path        path.Path
	project     *vagrant_server.Project
	ui          terminal.UI
	vagrant     *serverclient.VagrantClient
	vagrantfile path.Path
}

// Finds the Vagrantfile associated with the project
func (p *Project) LoadVagrantfile() error {
	l := p.logger.With(
		"basis", p.basis.basis.Name,
		"project", p.project.Name,
		"path", p.vagrantfile,
	)
	l.Trace("attempting to load project vagrantfile")
	if p.vagrantfile == nil {
		l.Warn("project vagrantfile has not been set")
		return nil
	}

	// If the path does not exist, no Vagrantfile was found
	if _, err := os.Stat(p.vagrantfile.String()); os.IsNotExist(err) {
		l.Warn("project vagrantfile does not exist")
		return nil
	}

	raw, err := p.client.rubyRuntime.Dispense("vagrantrubyruntime")
	if err != nil {
		l.Warn("failed to load ruby runtime for vagrantfile parsing",
			"error", err,
		)

		return err
	}

	vp, err := LoadVagrantfile(
		p.vagrantfile, l, raw.(serverclient.RubyVagrantClient))

	if err != nil {
		return err
	}

	p.project.Configuration = vp
	p.project.Basis = p.basis.Ref()
	// Push Vagrantfile updates to project
	result, err := p.vagrant.UpsertProject(
		p.ctx,
		&vagrant_server.UpsertProjectRequest{
			Project: p.project,
		},
	)

	if err != nil {
		l.Error("failed to store project updates",
			"error", err,
		)

		return err
	}
	p.project = result.Project

	return nil
}

func (p *Project) LoadTarget(n string) (*Target, error) {
	result, err := p.vagrant.FindTarget(
		p.ctx,
		&vagrant_server.FindTargetRequest{
			Target: &vagrant_server.Target{
				Name:    n,
				Project: p.Ref(),
			},
		},
	)
	if err != nil {
		return nil, err
	}

	// If the target exists, load and return
	if result != nil {
		return &Target{
			client:  p.client,
			ctx:     p.ctx,
			logger:  p.logger.Named("target"),
			project: p,
			target:  result.Target,
			ui:      p.ui,
			vagrant: p.vagrant,
		}, nil
	}

	// TODO(spox): Some adjustment is needed on how targets
	//             should be loaded here when their origin
	//             will be the vagrantfile
	return nil, fmt.Errorf("cannot load target")
}

func (p *Project) UI() terminal.UI {
	return p.ui
}

func (p *Project) Close() error {
	return p.basis.Close()
}

// Ref returns the raw Vagrant server API client.
func (p *Project) Ref() *vagrant_plugin_sdk.Ref_Project {
	return &vagrant_plugin_sdk.Ref_Project{
		Name:       p.project.Name,
		ResourceId: p.project.ResourceId,
		Basis:      p.basis.Ref(),
	}
}