forked from tilt-dev/tilt-extensions
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Tiltfile
198 lines (152 loc) · 7.85 KB
/
Tiltfile
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# Find the directory where Tilt loaded modules.
# This is usually the XDG data directory for tilt data.
def _find_tilt_modules_load_dir():
current = os.path.abspath('./')
while True:
if os.path.exists(os.path.join(current, 'tilt_modules')):
return current
next_dir = os.path.dirname(current)
if next_dir == current:
fail('Could not find root Tiltfile')
current = next_dir
def _find_checkout_dir():
from_env = os.getenv('TILT_GIT_RESOURCE_CHECKOUT_DIR', '')
if from_env != '':
return from_env
return os.path.join(_find_tilt_modules_load_dir(), '.git-sources')
# this is the root directory into which remote git repositories will be cloned
# use `os.putenv('TILT_GIT_RESOURCE_CHECKOUT_DIR', new_dir)` to change
# if customizing this location, you will also need to add the new location to your .tiltignore file to prevent infinite loops processing the main tiltfile (See github [issue #3404](https://github.com/tilt-dev/tilt/issues/3404))
git_resource_checkout_dir = _find_checkout_dir()
def git_resource(resource_name, path_or_repo, dockerfile='Dockerfile', namespace='default', resource_deps=[], port_forwards=[], build_callback=None, deployment_callback=None):
is_http = path_or_repo[:4].lower() == 'http'
is_ssh = path_or_repo[:4].lower() == 'git@'
is_local = not is_http and not is_ssh
if is_local:
deploy_from_dir(resource_name, path_or_repo, dockerfile=dockerfile, namespace=namespace, resource_deps=resource_deps, port_forwards=port_forwards, build_callback=build_callback, deployment_callback=deployment_callback)
else:
deploy_from_repository(resource_name, path_or_repo, dockerfile=dockerfile, namespace=namespace, resource_deps=resource_deps, port_forwards=port_forwards, build_callback=build_callback, deployment_callback=deployment_callback)
def git_checkout(repository_url, checkout_dir=None, unsafe_mode=False):
if checkout_dir == '' or checkout_dir == None:
checkout_dir = _get_default_checkout_target(repository_url)
repository_url, _, tree = _parse_repository_url(repository_url) # split the branch name away from the repo url
if config.tilt_subcommand == "up" or config.tilt_subcommand == "ci":
is_branch = tree.startswith('#')
is_revision = tree.startswith('@')
is_tag = tree.startswith('#tags/')
tree = tree[1:]
if is_tag:
tree = tree[5:]
if tree.startswith('origin/'):
tree = tree[7:]
if not os.path.exists(checkout_dir): # needs clone
clone_cmd = ['git','clone', repository_url, '--recurse-submodules', '--shallow-submodules']
if is_branch or is_tag:
clone_cmd.extend(['--depth', '1', '--no-single-branch'])
if tree:
clone_cmd.extend(['--branch', tree])
clone_cmd.append(checkout_dir)
local(clone_cmd, quiet=True)
else:
clone_cmd.append(checkout_dir)
local(clone_cmd, quiet=True)
if tree:
local(['git', 'checkout', tree], dir=checkout_dir)
else: # dir already exists
if os.path.exists(os.path.join(checkout_dir, '.git')): # this is a git repo
has_local_changes = True # default to True for safety
if not unsafe_mode:
local_changes = str(local(
command='git status -sbuno',
quiet=True,
echo_off=True,
dir=checkout_dir,
)).strip().splitlines()
# result greater than 1 indicates local modifications are present
has_local_changes = len(local_changes) > 1
if unsafe_mode or not has_local_changes:
checkout_cmd = None
if tree:
checkout_branch = tree
if not is_tag and not is_revision:
checkout_branch = 'origin/%s' % tree
checkout_cmd = 'git checkout -f %s' % checkout_branch
local('git fetch -a origin', dir=checkout_dir, quiet=True)
if checkout_cmd:
local(checkout_cmd, dir=checkout_dir, quiet=True)
local('git submodule update --init', dir=checkout_dir, quiet=True)
else:
fail('git_checkout() failed: local modifications present and safe_mode is enabled')
else: # this isn't a git repo
fail('git_checkout() failed: existing checkout_dir is not a git repository')
return checkout_dir
def deploy_from_dir(resource_name, directory, dockerfile='Dockerfile', namespace='default', resource_deps=[], port_forwards=[], build_callback=None, deployment_callback=None):
if deployment_callback == None:
deployment_callback = lambda resource_name, image_name, namespace: _default_deployment_callback(resource_name, image_name, namespace)
if build_callback == None:
build_callback = lambda resource_name, directory, dockerfile: _default_build_callback(resource_name, directory, dockerfile=dockerfile)
image_name = build_callback(resource_name, directory, dockerfile=dockerfile)
yaml = deployment_callback(resource_name, image_name, namespace)
k8s_yaml(yaml)
k8s_resource(resource_name, resource_deps=resource_deps, port_forwards=port_forwards)
def deploy_from_repository(name, repository_url, dockerfile='Dockerfile', namespace='default', resource_deps=[], port_forwards=[], build_callback=None, deployment_callback=None):
checkout_path = git_checkout(repository_url)
deploy_from_dir(name, checkout_path, dockerfile=dockerfile, namespace=namespace, resource_deps=resource_deps, port_forwards=port_forwards, build_callback=build_callback, deployment_callback=deployment_callback)
def _parse_repository_url(url):
is_ssh = url.startswith('git@')
if is_ssh:
url = url[4:]
splitter = None
if '#' in url:
splitter = '#'
elif '@' in url:
splitter = '@'
if splitter == None:
tree = ''
else:
parts = url.split(splitter)
tree = splitter + parts[-1] # last item
# Make sure we didn't peel of a scheme://user@host/ url
if splitter == '@' and '/' in tree:
tree = ''
else:
url = splitter.join(parts[:-1]) # everything else
if is_ssh:
url = 'git@' + url
repository_name = os.path.basename(url).rstrip('.git')
return url, repository_name, simple_url_decode(tree)
# in case the branch name contains '#' or '@', these need to be escaped
def simple_url_decode(tree):
return tree.replace('%23', '#').replace('%40', '@')
def _get_default_checkout_target(repository_url):
url, repository_name, branch = _parse_repository_url(repository_url)
checkout_dir = os.path.join(git_resource_checkout_dir, repository_name)
return checkout_dir
def _default_build_callback(resource_name, context, dockerfile='Dockerfile'): # returns resultant image name
image_name = resource_name + '-image'
docker_build(image_name, context, dockerfile=os.path.join(context, dockerfile), ssh='default')
return image_name
def _default_deployment_callback(resource_name, image_name, namespace='default'): # returns deployment definition yaml
"""Returns YAML for a generic deployment
Args: image_name: The name of the image to deploy. Currently not validated.
"""
return blob("""apiVersion: apps/v1
kind: Deployment
metadata:
name: %s
namespace: %s
labels:
app: %s
spec:
selector:
matchLabels:
app: %s
template:
metadata:
labels:
app: %s
spec:
containers:
- name: %s
image: %s
""" % (resource_name, namespace, resource_name, resource_name, resource_name, resource_name, image_name))