Skip to content

Commit ed27d00

Browse files
Fixed several potential issues and cleaned up code.
1 parent 07ff430 commit ed27d00

File tree

5 files changed

+150
-76
lines changed

5 files changed

+150
-76
lines changed

ament_virtualenv/ament_virtualenv/build_venv.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ def main(argv=sys.argv[1:]):
8181
)
8282
parser.add_argument(
8383
'--python-version',
84+
required=True,
8485
help="Build the virtualenv with which python major version."
8586
)
8687
parser.add_argument(
@@ -100,22 +101,28 @@ def main(argv=sys.argv[1:]):
100101
type=str,
101102
help="Extra pip args for install."
102103
)
103-
104104
args, unknown = parser.parse_known_args()
105+
return build_venv(
106+
root_dir=args.root_dir,
107+
python_version=args.python_version,
108+
requirements_filename=args.requirements,
109+
use_system_packages=args.use_system_packages,
110+
extra_pip_args=args.extra_pip_args[1:-1],
111+
retries=args.retries
112+
)
105113

106-
root_dir = os.path.realpath(args.root_dir)
107-
114+
def build_venv(root_dir, python_version, requirements_filename, use_system_packages=False, extra_pip_args="", retries=0):
115+
root_dir = os.path.realpath(root_dir)
116+
python_executable = find_python(python_version)
108117
os.environ['DH_VIRTUALENV_INSTALL_ROOT'] = os.path.dirname(root_dir)
109118

110-
python_executable = find_python(args.python_version)
111-
112119
deploy = Deployment(
113120
package=os.path.basename(root_dir),
114-
requirements_filename=args.requirements,
121+
requirements_filename=requirements_filename,
115122
upgrade_pip=True,
116-
use_system_packages=args.use_system_packages,
123+
use_system_packages=use_system_packages,
117124
python=python_executable,
118-
extra_pip_arg=args.extra_pip_args[1:-1].split(' '),
125+
extra_pip_arg=extra_pip_args.split(' '),
119126
log_file=None,
120127
builtin_venv=check_module(python_executable, 'venv'),
121128
builtin_pip=check_module(python_executable, 'pip'),
@@ -127,7 +134,7 @@ def main(argv=sys.argv[1:]):
127134
print('Generating virtualenv in {}'.format(deploy.package_dir))
128135
deploy.create_virtualenv()
129136

130-
print('Installing requirements')
137+
print('Installing requirements from {}'.format(deploy.requirements_filename))
131138
deploy.install_dependencies()
132139

133140
print('Fixing virtualenv root to {}'.format(deploy.virtualenv_install_dir))
@@ -143,8 +150,8 @@ def main(argv=sys.argv[1:]):
143150
# Remove local folder
144151
shutil.rmtree(local_dir)
145152
except Exception as e:
146-
args.retries -= 1
147-
if args.retries >= 0:
153+
retries -= 1
154+
if retries >= 0:
148155
print("Error, clearing virtualenv and retrying: {}".format(e), file=sys.stderr)
149156
try:
150157
shutil.rmtree(root_dir)
@@ -153,12 +160,11 @@ def main(argv=sys.argv[1:]):
153160
continue
154161
else:
155162
raise
156-
157163
break
158164

159165
return 0
160166
#
161167

162168

163169
if __name__ == "__main__":
164-
main()
170+
sys.exit(main())

ament_virtualenv/ament_virtualenv/combine_requirements.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,4 @@ def main(argv=sys.argv[1:]):
9797

9898

9999
if __name__ == "__main__":
100-
main()
100+
sys.exit(main())

ament_virtualenv/ament_virtualenv/glob_requirements.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,13 @@
3434

3535

3636
def find_in_workspaces(project, file):
37-
paths = os.environ.get('AMENT_PREFIX_PATH')
37+
paths = os.environ.get('COLCON_PREFIX_PATH')
3838
if not paths:
3939
return None
4040
paths = paths.split(os.pathsep)
4141
workspaces = []
4242
for path in paths:
43-
if '/install/' in path:
44-
workspaces.append(path)
43+
workspaces.append(os.path.join(path, project))
4544
# should be at share/ament_virtualenv/
4645
search_dirs = ['etc', 'include', 'libexec', 'share']
4746
if 'libexec' in search_dirs:
@@ -126,18 +125,18 @@ def glob_requirements(package_name, no_deps):
126125
for dependency in dependencies:
127126
package_queue.put(dependency.name)
128127

129-
print(';'.join(requirements_list))
130-
return 0
128+
return ';'.join(requirements_list)
131129

132130

133131
def main(argv=sys.argv[1:]):
134132
parser = argparse.ArgumentParser()
135133
parser.add_argument('--package-name', type=str, required=True)
136134
parser.add_argument('--no-deps', action="store_true")
137135
args, unknown = parser.parse_known_args()
138-
return glob_requirements(**vars(args))
136+
print(glob_requirements(**vars(args)))
137+
return 0
139138
#
140139

141140

142141
if __name__ == "__main__":
143-
main()
142+
sys.exit(main())

ament_virtualenv/ament_virtualenv/install.py

Lines changed: 106 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,23 @@
2626
import sys
2727
import subprocess
2828
import shutil
29-
import importlib
30-
import unittest
3129
import psutil
30+
import argparse
3231

32+
try:
33+
from ament_virtualenv.glob_requirements import glob_requirements
34+
from ament_virtualenv.combine_requirements import combine_requirements
35+
from ament_virtualenv.build_venv import build_venv
36+
ament_virtualenv_import_failed = False
37+
except:
38+
ament_virtualenv_import_failed = True
39+
#
3340

3441
def find_program(name='build_venv.py', package='ament_virtualenv'):
3542
'''
43+
Helper function to find the modules that are part of this
44+
package (glob_requirements, combine_requirements, build_venv),
45+
in cases where a direct import failes due to python path issues.
3646
'''
3747
ament_prefix_path = os.environ.get("AMENT_PREFIX_PATH")
3848
if not ament_prefix_path:
@@ -52,58 +62,90 @@ def find_program(name='build_venv.py', package='ament_virtualenv'):
5262
def install_venv(install_base, package_name, python_version='2'):
5363
venv_install_dir = os.path.join(install_base, 'venv')
5464
bin_dir = os.path.join(install_base, 'bin')
55-
#
65+
#
5666
# Build the virtual environment
5767
python = shutil.which("python")
5868
if not python:
5969
print("ERROR: Failed to locate python", file=sys.stderr)
60-
return
70+
return 1
6171

6272
# glob_requirements --package-name ament_cmake_haros
63-
glob_requirements = find_program(name='glob_requirements.py', package='ament_virtualenv')
64-
if not glob_requirements:
65-
print("ERROR: Failed to locate glob_requirements", file=sys.stderr)
66-
return
67-
cmd = [
68-
python,
69-
glob_requirements,
70-
'--package-name',
71-
package_name
72-
]
73-
requirements_list = subprocess.check_output(cmd)
74-
requirements_list = requirements_list.decode("utf-8").strip()
75-
76-
# combine_requirements --requirements-list a/requirements.txt;b/requirements.txt --output-file x/generated_requirements.txt
77-
combine_requirements = find_program(name='combine_requirements.py', package='ament_virtualenv')
78-
if not combine_requirements:
79-
print("ERROR: Failed to locate combine_requirements", file=sys.stderr)
80-
return
73+
if ament_virtualenv_import_failed == True:
74+
# Fallback: try to find the command line script and run it
75+
glob_requirements_py = find_program(name='glob_requirements.py', package='ament_virtualenv')
76+
if not glob_requirements_py:
77+
print("ERROR: Failed to locate glob_requirements", file=sys.stderr)
78+
return 1
79+
cmd = [
80+
python,
81+
glob_requirements_py,
82+
'--package-name',
83+
package_name
84+
]
85+
requirements_list = subprocess.check_output(cmd)
86+
requirements_list = requirements_list.decode("utf-8").strip()
87+
else:
88+
# Use the module directly
89+
requirements_list = glob_requirements(package_name=package_name, no_deps=False)
90+
# ^ glob_requirements
91+
#
92+
# combine_requirements --requirements-list a/requirements.txt;b/requirements.txt
93+
# --output-file x/generated_requirements.txt
8194
generated_requirements = '/tmp/test_ament_virtualenv-generated_requirements.txt'
82-
cmd = [
83-
python,
84-
combine_requirements,
85-
'--requirements-list',
86-
requirements_list,
87-
'--output-file',
88-
generated_requirements
89-
]
90-
subprocess.check_output(cmd)
91-
92-
build_venv = find_program(name='build_venv.py', package='ament_virtualenv')
93-
if not build_venv:
94-
print("ERROR: Failed to locate build_venv", file=sys.stderr)
95-
return
96-
cmd = [
97-
python,
98-
build_venv,
99-
'--root-dir', venv_install_dir,
100-
'--requirements', generated_requirements,
101-
'--retries', '3',
102-
'--python-version', python_version,
103-
# '--use-system-packages',
104-
'--extra-pip-args', '\"-qq\"',
105-
]
106-
ret = subprocess.check_output(cmd)
95+
if ament_virtualenv_import_failed:
96+
combine_requirements_py = find_program(name='combine_requirements.py', package='ament_virtualenv')
97+
if not combine_requirements_py:
98+
print("ERROR: Failed to locate combine_requirements", file=sys.stderr)
99+
return 1
100+
cmd = [
101+
python,
102+
combine_requirements_py,
103+
'--requirements-list',
104+
requirements_list,
105+
'--output-file',
106+
generated_requirements
107+
]
108+
subprocess.check_output(cmd)
109+
else:
110+
requirements_files = []
111+
for requirements_file in requirements_list.split(';'):
112+
requirements_files.append(open(requirements_file, 'r'))
113+
generated_requirements_file = open(generated_requirements, 'w')
114+
combine_requirements(
115+
requirements_list=requirements_files,
116+
output_file=generated_requirements_file
117+
)
118+
for requirements_file in requirements_files:
119+
requirements_file.close()
120+
generated_requirements_file.close()
121+
# ^ combine_requirements
122+
#
123+
if ament_virtualenv_import_failed:
124+
build_venv_py = find_program(name='build_venv.py', package='ament_virtualenv')
125+
if not build_venv_py:
126+
print("ERROR: Failed to locate build_venv", file=sys.stderr)
127+
return 1
128+
cmd = [
129+
python,
130+
build_venv_py,
131+
'--root-dir', venv_install_dir,
132+
'--requirements', generated_requirements,
133+
'--retries', '3',
134+
'--python-version', python_version,
135+
# '--use-system-packages',
136+
'--extra-pip-args', '\"-qq\"',
137+
]
138+
ret = subprocess.check_output(cmd)
139+
else:
140+
ret = build_venv(
141+
root_dir=venv_install_dir,
142+
python_version=python_version,
143+
requirements_filename=generated_requirements,
144+
use_system_packages=False,
145+
extra_pip_args="-qq",
146+
retries=3
147+
)
148+
print('XXXXXXXX build_venv returned ' + str(ret))
107149
#
108150
# Wrapper shell executables we installed
109151
for bin_file in os.listdir(bin_dir):
@@ -114,6 +156,7 @@ def install_venv(install_base, package_name, python_version='2'):
114156
if not os.path.isfile(bin_path):
115157
continue
116158
os.rename(bin_path, bin_path+'-venv')
159+
venv_rel_path = os.path.relpath(venv_install_dir, bin_dir)
117160
# create new file with the name of the previous file
118161
with open(bin_path, "w") as f:
119162
f.write("#!/usr/bin/python3\n")
@@ -123,16 +166,28 @@ def install_venv(install_base, package_name, python_version='2'):
123166
f.write("if __name__ == '__main__':\n")
124167
f.write(" dir_path = os.path.dirname(os.path.realpath(__file__))\n")
125168
f.write(" bin_path = os.path.join(dir_path, '" + bin_file + "-venv')\n")
126-
f.write(" cmd = '" + venv_install_dir + "/bin/python ' + bin_path\n")
169+
f.write(" vpy_path = os.path.abspath(os.path.join(dir_path, '" + venv_rel_path +"'))\n")
170+
f.write(" vpy_path = os.path.join(vpy_path, 'bin', 'python')\n")
171+
f.write(" cmd = vpy_path + ' ' + bin_path\n")
127172
f.write(" sys.exit(subprocess.call(cmd, shell=True))\n")
128173
# change file permissions to executable
129174
st = os.stat(bin_path)
130175
os.chmod(bin_path, st.st_mode | stat.S_IEXEC | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
131-
176+
#
177+
return 0
132178

133179
def main(argv=sys.argv[1:]):
134-
return 0 # todo
180+
parser = argparse.ArgumentParser()
181+
parser.add_argument('--install-base', required=True)
182+
parser.add_argument('--package-name', required=True)
183+
parser.add_argument('--python-version', required=True)
184+
args, unknown = parser.parse_known_args()
185+
return install_venv(
186+
install_base=args.install_base,
187+
package_name=args.package_name,
188+
python_version=args.python_version
189+
)
135190

136191

137192
if __name__ == "__main__":
138-
main()
193+
sys.exit(main())

test_ament_virtualenv/test_ament_virtualenv/test_ament_virtualenv.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,34 @@ def main(args=None):
2525
# 1: Test if we're in a virtual environment at all.
2626
is_in_venv = hasattr(sys, 'real_prefix')
2727
if not is_in_venv:
28-
print("[test_ament_virtualenv] FAILURE: Python virtual environment not activated.")
28+
print(
29+
"[test_ament_virtualenv] "
30+
"FAILURE: Python virtual environment not activated."
31+
)
2932
return 1
3033
# 2: Test the Python version.
3134
if sys.version_info.major != 2:
32-
print("[test_ament_virtualenv] FAILURE: Wrong Python version.")
35+
print(
36+
"[test_ament_virtualenv] "
37+
"FAILURE: Wrong Python version."
38+
)
3339
return 1
3440
# 3: Test if proper requirements have been installed
3541
try:
3642
requests = importlib.import_module("requests")
3743
if requests.__version__ != '2.20.1':
38-
print("[test_ament_virtualenv] FAILURE: Requirements not provided correctly.")
44+
print(
45+
"[test_ament_virtualenv] "
46+
"FAILURE: Requirements not provided correctly "
47+
"(expected 'requests==2.20.1', found "+requests.__version__+")"
48+
)
3949
return 1
4050
except:
41-
print("[test_ament_virtualenv] FAILURE: Requirements not provided.")
51+
print(
52+
"[test_ament_virtualenv] "
53+
"FAILURE: Requirements not provided "
54+
"(expected 'requests' to be present but could not find it)"
55+
)
4256
return 1
4357
print("[test_ament_virtualenv] SUCCESS: All checks passed.")
4458
return 0

0 commit comments

Comments
 (0)