22
33import os
44import platform
5+ import shutil
56import sys
67import tarfile
78
1011from setuptools import setup
1112from setuptools .command .develop import develop
1213from setuptools .command .install import install
14+ from distutils .command .sdist import sdist as sdist_orig
1315
1416
1517IS_64 = sys .maxsize > 2 ** 32
1618PACT_STANDALONE_VERSION = '1.88.51'
17-
19+ PACT_STANDALONE_SUFFIXES = ['osx.tar.gz' ,
20+ 'linux-x86_64.tar.gz' ,
21+ 'linux-x86.tar.gz' ,
22+ 'win32.zip' ]
1823
1924here = os .path .abspath (os .path .dirname (__file__ ))
2025
2126about = {}
2227with open (os .path .join (here , "pact" , "__version__.py" )) as f :
2328 exec (f .read (), about )
2429
30+ class sdist (sdist_orig ):
31+ """
32+ Subclass sdist so that we can download all standalone ruby applications
33+ into ./pact/bin so our users receive all the binaries on pip install.
34+ """
35+ def run (self ):
36+ package_bin_path = os .path .join (os .path .dirname (__file__ ), 'pact' , 'bin' )
37+
38+ if os .path .exists (package_bin_path ):
39+ shutil .rmtree (package_bin_path , ignore_errors = True )
40+ os .mkdir (package_bin_path )
41+
42+ for suffix in PACT_STANDALONE_SUFFIXES :
43+ filename = ('pact-{version}-{suffix}' ).format (version = PACT_STANDALONE_VERSION , suffix = suffix )
44+ download_ruby_app_binary (package_bin_path , filename , suffix )
45+ super ().run ()
46+
2547
2648class PactPythonDevelopCommand (develop ):
2749 """
@@ -35,11 +57,11 @@ class PactPythonDevelopCommand(develop):
3557 def run (self ):
3658 """Install ruby command."""
3759 develop .run (self )
38- bin_path = os .path .join (os .path .dirname (__file__ ), 'pact' , 'bin' )
39- if not os .path .exists (bin_path ):
40- os .mkdir (bin_path )
60+ package_bin_path = os .path .join (os .path .dirname (__file__ ), 'pact' , 'bin' )
61+ if not os .path .exists (package_bin_path ):
62+ os .mkdir (package_bin_path )
4163
42- install_ruby_app (bin_path )
64+ install_ruby_app (package_bin_path , download_bin_path = None )
4365
4466
4567class PactPythonInstallCommand (install ):
@@ -48,25 +70,66 @@ class PactPythonInstallCommand(install):
4870
4971 Installs the Python package and unpacks the platform appropriate version
5072 of the Ruby mock service and provider verifier.
73+
74+ User Options:
75+ --bin-path An absolute folder path containing predownloaded pact binaries
76+ that should be used instead of fetching from the internet.
5177 """
5278
79+ user_options = install .user_options + [('bin-path=' , None , None )]
80+
81+ def initialize_options (self ):
82+ """Load our preconfigured options"""
83+ install .initialize_options (self )
84+ self .bin_path = None
85+
86+ def finalize_options (self ):
87+ """Load provided CLI arguments into our options"""
88+ install .finalize_options (self )
89+
5390 def run (self ):
5491 """Install python binary."""
5592 install .run (self )
56- bin_path = os .path .join (self .install_lib , 'pact' , 'bin' )
57- os .mkdir (bin_path )
58- install_ruby_app (bin_path )
93+ package_bin_path = os .path .join (self .install_lib , 'pact' , 'bin' )
94+ if not os .path .exists (package_bin_path ):
95+ os .mkdir (package_bin_path )
96+ install_ruby_app (package_bin_path , self .bin_path )
5997
6098
61- def install_ruby_app (bin_path ):
99+ def install_ruby_app (package_bin_path , download_bin_path ):
62100 """
63- Download a Ruby application and install it for use .
101+ Installs the ruby standalone application for this OS .
64102
65- :param bin_path: The path where binaries should be installed.
103+ :param package_bin_path: The path where we want our pact binaries unarchived.
104+ :param download_bin_path: An optional path containing pre-downloaded pact binaries.
105+ """
106+
107+ binary = ruby_app_binary ()
108+ if download_bin_path is None :
109+ download_bin_path = package_bin_path
110+
111+ path = os .path .join (download_bin_path , binary ['filename' ])
112+
113+ if os .path .isfile (path ) is True :
114+ extract_ruby_app_binary (download_bin_path , package_bin_path , binary ['filename' ])
115+ else :
116+ if download_bin_path is not None :
117+ if os .path .isfile (path ) is not True :
118+ raise RuntimeError ('Could not find {} binary.' .format (path ))
119+ extract_ruby_app_binary (download_bin_path , package_bin_path , binary ['filename' ])
120+ else :
121+ download_ruby_app_binary (package_bin_path , binary ['filename' ], binary ['suffix' ])
122+ extract_ruby_app_binary (package_bin_path , package_bin_path , binary ['filename' ])
123+
124+ def ruby_app_binary ():
125+ """
126+ Determines the ruby app binary required for this OS.
127+
128+ :return A dictionary of type {'filename': string, 'version': string, 'suffix': string }
66129 """
67130 target_platform = platform .platform ().lower ()
68- uri = ( 'https://github.com/pact-foundation/pact-ruby-standalone/releases'
69- '/download/v{version}/ pact-{version}-{suffix}' )
131+
132+ binary = ( ' pact-{version}-{suffix}' )
70133
71134 if 'darwin' in target_platform or 'macos' in target_platform :
72135 suffix = 'osx.tar.gz'
@@ -82,12 +145,26 @@ def install_ruby_app(bin_path):
82145 platform .platform ())
83146 raise Exception (msg )
84147
148+ binary = binary .format (version = PACT_STANDALONE_VERSION , suffix = suffix )
149+ return {'filename' : binary , 'version' : PACT_STANDALONE_VERSION , 'suffix' : suffix }
150+
151+ def download_ruby_app_binary (path_to_download_to , filename , suffix ):
152+ """
153+ Downloads `binary` into `path_to_download_to`.
154+
155+ :param path_to_download_to: The path where binaries should be downloaded.
156+ :param filename: The filename that should be installed.
157+ :param suffix: The suffix of the standalone app to install.
158+ """
159+ uri = ('https://github.com/pact-foundation/pact-ruby-standalone/releases'
160+ '/download/v{version}/pact-{version}-{suffix}' )
161+
85162 if sys .version_info .major == 2 :
86163 from urllib import urlopen
87164 else :
88165 from urllib .request import urlopen
89166
90- path = os .path .join (bin_path , suffix )
167+ path = os .path .join (path_to_download_to , filename )
91168 resp = urlopen (uri .format (version = PACT_STANDALONE_VERSION , suffix = suffix ))
92169 with open (path , 'wb' ) as f :
93170 if resp .code == 200 :
@@ -97,12 +174,21 @@ def install_ruby_app(bin_path):
97174 'Received HTTP {} when downloading {}' .format (
98175 resp .code , resp .url ))
99176
177+ def extract_ruby_app_binary (source , destination , binary ):
178+ """
179+ Extracts the ruby app binary from `source` into `destination`.
180+
181+ :param source: The location of the binary to unarchive.
182+ :param destination: The location to unarchive to.
183+ :param binary: The binary that needs to be unarchived.
184+ """
185+ path = os .path .join (source , binary )
100186 if 'windows' in platform .platform ().lower ():
101187 with ZipFile (path ) as f :
102- f .extractall (bin_path )
188+ f .extractall (destination )
103189 else :
104190 with tarfile .open (path ) as f :
105- f .extractall (bin_path )
191+ f .extractall (destination )
106192
107193
108194def read (filename ):
@@ -126,7 +212,8 @@ def read(filename):
126212 setup (
127213 cmdclass = {
128214 'develop' : PactPythonDevelopCommand ,
129- 'install' : PactPythonInstallCommand },
215+ 'install' : PactPythonInstallCommand ,
216+ 'sdist' : sdist },
130217 name = 'pact-python' ,
131218 version = about ['__version__' ],
132219 description = (
0 commit comments