1212from pathlib import Path
1313
1414import click
15+ import requests
1516
1617from airbyte_cdk .models .connector_metadata import ConnectorLanguage , MetadataFile
1718from airbyte_cdk .utils .connector_paths import resolve_airbyte_repo_root
18- from airbyte_cdk .utils .docker_image_templates import (
19- DOCKERIGNORE_TEMPLATE ,
20- JAVA_CONNECTOR_DOCKERFILE_TEMPLATE ,
21- MANIFEST_ONLY_DOCKERFILE_TEMPLATE ,
22- PYTHON_CONNECTOR_DOCKERFILE_TEMPLATE ,
23- )
2419
2520
2621@dataclass (kw_only = True )
@@ -165,20 +160,36 @@ def build_connector_image(
165160 ConnectorImageBuildError: If the image build or tag operation fails.
166161 """
167162 connector_kebab_name = connector_name
168- connector_snake_name = connector_kebab_name .replace ("-" , "_" )
169163
170164 if dockerfile_override :
171165 dockerfile_path = dockerfile_override
172166 else :
173167 dockerfile_path = connector_directory / "build" / "docker" / "Dockerfile"
174- dockerfile_path .write_text (
175- get_dockerfile_template (
176- metadata ,
177- connector_directory ,
178- )
179- )
180168 dockerignore_path = connector_directory / "build" / "docker" / "Dockerfile.dockerignore"
181- dockerignore_path .write_text (DOCKERIGNORE_TEMPLATE )
169+ try :
170+ dockerfile_text , dockerignore_text = get_dockerfile_templates (
171+ metadata = metadata ,
172+ connector_directory = connector_directory ,
173+ )
174+ except FileNotFoundError :
175+ # If the Dockerfile and .dockerignore are not found in the connector directory,
176+ # download the templates from the Airbyte repo. This is a fallback
177+ # in case the Airbyte repo not checked out locally.
178+ try :
179+ dockerfile_text , dockerignore_text = _download_dockerfile_defs (
180+ connector_language = metadata .data .language ,
181+ )
182+ except requests .HTTPError as e :
183+ raise ConnectorImageBuildError (
184+ build_args = [],
185+ error_text = (
186+ "Could not locate local dockerfile templates and "
187+ f"failed to download Dockerfile templates from github: { e } "
188+ ),
189+ ) from e
190+
191+ dockerfile_path .write_text (dockerfile_text )
192+ dockerignore_path .write_text (dockerignore_text )
182193
183194 extra_build_script : str = ""
184195 build_customization_path = connector_directory / "build_customization.py"
@@ -249,18 +260,67 @@ def build_connector_image(
249260 sys .exit (0 )
250261
251262
252- def get_dockerfile_template (
263+ def _download_dockerfile_defs (
264+ connector_language : ConnectorLanguage ,
265+ ) -> tuple [str , str ]:
266+ """Download the Dockerfile and .dockerignore templates for the specified connector language.
267+
268+ We use the requests library to download from the master branch hosted on GitHub.
269+
270+ Args:
271+ connector_language: The language of the connector.
272+
273+ Returns:
274+ A tuple containing the Dockerfile and .dockerignore templates as strings.
275+
276+ Raises:
277+ ValueError: If the connector language is not supported.
278+ requests.HTTPError: If the download fails.
279+ """
280+ print ("Downloading Dockerfile and .dockerignore templates from GitHub..." )
281+ # Map ConnectorLanguage to template directory
282+ language_to_template_suffix = {
283+ ConnectorLanguage .PYTHON : "python-connector" ,
284+ ConnectorLanguage .JAVA : "java-connector" ,
285+ ConnectorLanguage .MANIFEST_ONLY : "manifest-only-connector" ,
286+ }
287+
288+ if connector_language not in language_to_template_suffix :
289+ raise ValueError (f"Unsupported connector language: { connector_language } " )
290+
291+ template_suffix = language_to_template_suffix [connector_language ]
292+ base_url = f"https://github.com/airbytehq/airbyte/raw/master/docker-images/"
293+
294+ dockerfile_url = f"{ base_url } /Dockerfile.{ template_suffix } "
295+ dockerignore_url = f"{ base_url } /Dockerfile.{ template_suffix } .dockerignore"
296+
297+ dockerfile_resp = requests .get (dockerfile_url )
298+ dockerfile_resp .raise_for_status ()
299+ dockerfile_text = dockerfile_resp .text
300+
301+ dockerignore_resp = requests .get (dockerignore_url )
302+ dockerignore_resp .raise_for_status ()
303+ dockerignore_text = dockerignore_resp .text
304+
305+ return dockerfile_text , dockerignore_text
306+
307+
308+ def get_dockerfile_templates (
253309 metadata : MetadataFile ,
254310 connector_directory : Path ,
255- ) -> str :
311+ ) -> tuple [ str , str ] :
256312 """Get the Dockerfile template for the connector.
257313
258314 Args:
259315 metadata: The metadata of the connector.
260316 connector_name: The name of the connector.
261317
318+ Raises:
319+ ValueError: If the connector language is not supported.
320+ FileNotFoundError: If the Dockerfile or .dockerignore is not found.
321+
262322 Returns:
263- The Dockerfile template as a string .
323+ A tuple containing the Dockerfile and .dockerignore templates as strings .
264324 """
265325 if metadata .data .language not in [
266326 ConnectorLanguage .PYTHON ,
@@ -272,38 +332,28 @@ def get_dockerfile_template(
272332 "Please check the connector's metadata file."
273333 )
274334
275- try :
276- airbyte_repo_root = resolve_airbyte_repo_root (
277- from_dir = connector_directory ,
335+ airbyte_repo_root = resolve_airbyte_repo_root (
336+ from_dir = connector_directory ,
337+ )
338+ # airbyte_repo_root successfully resolved
339+ dockerfile_path = (
340+ airbyte_repo_root / "docker-images" / f"Dockerfile.{ metadata .data .language .value } -connector"
341+ )
342+ dockerignore_path = (
343+ airbyte_repo_root
344+ / "docker-images"
345+ / f"Dockerfile.{ metadata .data .language .value } -connector.dockerignore"
346+ )
347+ if not dockerfile_path .exists ():
348+ raise FileNotFoundError (
349+ f"Dockerfile for { metadata .data .language .value } connector not found at { dockerfile_path } "
278350 )
279- # airbyte_repo_root successfully resolved
280- dockerfile_path = (
281- airbyte_repo_root
282- / "docker-images"
283- / f"Dockerfile.{ metadata .data .language .value } -connector"
351+ if not dockerignore_path .exists ():
352+ raise FileNotFoundError (
353+ f".dockerignore for { metadata .data .language .value } connector not found at { dockerignore_path } "
284354 )
285- if not dockerfile_path .exists ():
286- raise FileNotFoundError (
287- f"Dockerfile for { metadata .data .language .value } connector not found at { dockerfile_path } "
288- )
289- return dockerfile_path .read_text ()
290-
291- except FileNotFoundError :
292- raise
293- if metadata .data .language == ConnectorLanguage .PYTHON :
294- return PYTHON_CONNECTOR_DOCKERFILE_TEMPLATE
295-
296- if metadata .data .language == ConnectorLanguage .MANIFEST_ONLY :
297- return MANIFEST_ONLY_DOCKERFILE_TEMPLATE
298-
299- if metadata .data .language == ConnectorLanguage .JAVA :
300- return JAVA_CONNECTOR_DOCKERFILE_TEMPLATE
301355
302- # Should not be reachable but we include to make linter happy:
303- raise ValueError (
304- f"Unsupported connector language: { metadata .data .language } . "
305- "Please check the connector's metadata file."
306- )
356+ return dockerfile_path .read_text (), dockerignore_path .read_text ()
307357
308358
309359def run_docker_command (
0 commit comments