autoverse-cli 0.28.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- autoverse_cli-0.28.1.dist-info/METADATA +91 -0
- autoverse_cli-0.28.1.dist-info/RECORD +51 -0
- autoverse_cli-0.28.1.dist-info/WHEEL +5 -0
- autoverse_cli-0.28.1.dist-info/entry_points.txt +2 -0
- autoverse_cli-0.28.1.dist-info/licenses/LICENSE +33 -0
- autoverse_cli-0.28.1.dist-info/top_level.txt +1 -0
- avrs/__init__.py +0 -0
- avrs/app_version.py +24 -0
- avrs/argparse_help.py +30 -0
- avrs/avrs.py +183 -0
- avrs/can_tool.py +192 -0
- avrs/can_tool_util.py +190 -0
- avrs/cfg.py +78 -0
- avrs/launcher.py +256 -0
- avrs/launcher_util.py +203 -0
- avrs/race_cloud.py +506 -0
- avrs/race_cloud_bridge_can.py +100 -0
- avrs/race_cloud_cfg_util.py +310 -0
- avrs/race_cloud_fwd_api.py +49 -0
- avrs/race_cloud_util.py +384 -0
- avrs/requests/change_camera.py +24 -0
- avrs/requests/code_booz.py +69 -0
- avrs/requests/demo.py +19 -0
- avrs/requests/dump_sim_config.py +14 -0
- avrs/requests/environment.py +46 -0
- avrs/requests/fault_injection.py +186 -0
- avrs/requests/get_object_config.py +18 -0
- avrs/requests/get_web_viz_meta.py +11 -0
- avrs/requests/leaderboard.py +74 -0
- avrs/requests/list_sim_objects.py +26 -0
- avrs/requests/log_path.py +28 -0
- avrs/requests/misc.py +70 -0
- avrs/requests/move_to_landmark.py +16 -0
- avrs/requests/npc.py +289 -0
- avrs/requests/race_control.py +48 -0
- avrs/requests/request.py +61 -0
- avrs/requests/reset_to_track.py +21 -0
- avrs/requests/rest_request.py +45 -0
- avrs/requests/restart.py +12 -0
- avrs/requests/scenario_control.py +43 -0
- avrs/requests/spawn_object.py +44 -0
- avrs/requests/teleport.py +40 -0
- avrs/requests/toggle_hud.py +11 -0
- avrs/requests/vd.py +64 -0
- avrs/requests/vehicle_input.py +21 -0
- avrs/requests/vehicle_replay.py +454 -0
- avrs/shell_completion.py +121 -0
- avrs/simconfig.py +75 -0
- avrs/simconfig_util.py +170 -0
- avrs/tests.py +9 -0
- avrs/util.py +13 -0
avrs/can_tool_util.py
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import can
|
|
2
|
+
import cantools
|
|
3
|
+
import time
|
|
4
|
+
import os
|
|
5
|
+
import datetime
|
|
6
|
+
import threading
|
|
7
|
+
import queue
|
|
8
|
+
import json
|
|
9
|
+
import math
|
|
10
|
+
import statistics
|
|
11
|
+
|
|
12
|
+
def get_eav24_hl0(throttle, gear, brake):
|
|
13
|
+
return {
|
|
14
|
+
"HL_TargetThrottle": throttle,
|
|
15
|
+
"HL_TargetGear": gear,
|
|
16
|
+
"HL_TargetPressure_RR": brake,
|
|
17
|
+
"HL_TargetPressure_RL": brake,
|
|
18
|
+
"HL_TargetPressure_FR": brake,
|
|
19
|
+
"HL_TargetPressure_FL": brake,
|
|
20
|
+
"HL_Alive_01": 0
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
def get_eav24_hl2(steer):
|
|
24
|
+
return {
|
|
25
|
+
"HL_Alive_02": 0,
|
|
26
|
+
"HL_PSA_Profile_Vel_rad_s": 0,
|
|
27
|
+
"HL_PSA_Profile_Dec_rad_s2": 0,
|
|
28
|
+
"HL_PSA_Profile_Acc_rad_s2": 0,
|
|
29
|
+
"HL_TargetPSAControl": steer,
|
|
30
|
+
"HL_PSA_ModeOfOperation": 0
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
def get_eav24_msigs(dbc, throttle, gear, brake, steer):
|
|
34
|
+
return {
|
|
35
|
+
dbc.get_message_by_name('HL_Msg_01'): get_eav24_hl0(throttle, gear, brake),
|
|
36
|
+
dbc.get_message_by_name('HL_Msg_02'): get_eav24_hl2(steer)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
def send_eav24_can_values(can_name, dbc, throttle, gear, brake, steer, duration, rate = 100):
|
|
40
|
+
with can.interface.Bus(can_name, bustype='socketcan') as bus:
|
|
41
|
+
message_1 = dbc.get_message_by_name('HL_Msg_01')
|
|
42
|
+
message_2 = dbc.get_message_by_name('HL_Msg_02')
|
|
43
|
+
print('sending EAV24 CAN inputs on {} with throttle {}, gear {}, brake {}, steer {}, for {} seconds'.format(can_name, throttle, gear, brake, steer, duration))
|
|
44
|
+
signals_1 = get_eav24_hl0(throttle, gear, brake)
|
|
45
|
+
signals_2 = get_eav24_hl2(steer)
|
|
46
|
+
|
|
47
|
+
msigs = get_eav24_msigs(dbc, throttle, gear, brake, steer)
|
|
48
|
+
send_eav24_can_signals(bus, msigs, rate, duration)
|
|
49
|
+
|
|
50
|
+
def send_eav24_can_signals(bus, message_signals, rate, duration):
|
|
51
|
+
start_time = time.time()
|
|
52
|
+
while time.time() - start_time < duration:
|
|
53
|
+
for msg, sig in message_signals.items():
|
|
54
|
+
bus.send(can.Message(arbitration_id=msg.frame_id, data=msg.encode(sig), is_extended_id=False))
|
|
55
|
+
time.sleep(1.0 / rate)
|
|
56
|
+
|
|
57
|
+
def test_eav24_can_latency(can_name, dbc, nsamples, send_rate, duration, save_report_as):
|
|
58
|
+
with can.interface.Bus(can_name, bustype='socketcan') as bus:
|
|
59
|
+
delays = []
|
|
60
|
+
times = []
|
|
61
|
+
|
|
62
|
+
for i in range(nsamples):
|
|
63
|
+
print('test {}'.format(i))
|
|
64
|
+
start_time = time.time()
|
|
65
|
+
last_throttle_time = time.time()
|
|
66
|
+
last_throttle_value = 50;
|
|
67
|
+
|
|
68
|
+
msigs = get_eav24_msigs(dbc, last_throttle_value, 1, 0, 0)
|
|
69
|
+
|
|
70
|
+
send_thread = threading.Thread(target=send_eav24_can_signals, args=(bus, msigs, send_rate, duration))
|
|
71
|
+
send_thread.start()
|
|
72
|
+
|
|
73
|
+
is_back_to_zero = False
|
|
74
|
+
while not is_back_to_zero:
|
|
75
|
+
message = bus.recv()
|
|
76
|
+
if message is not None:
|
|
77
|
+
decoded = decode_can_message(dbc, message)
|
|
78
|
+
if decoded and decoded['name'] == 'ICE_Status_01':
|
|
79
|
+
ack_value = decoded['data']['ICE_TargetThrottle_ACK']
|
|
80
|
+
if math.isclose(ack_value, last_throttle_value):
|
|
81
|
+
t = time.time()
|
|
82
|
+
#print('got throttle ack matching command at t{}'.format(t - last_throttle_time))
|
|
83
|
+
delay = t - last_throttle_time
|
|
84
|
+
delays.append(delay)
|
|
85
|
+
times.append(t)
|
|
86
|
+
print('got throttle ack for command {} after {} seconds'.format(last_throttle_value, delay))
|
|
87
|
+
if last_throttle_value == 0:
|
|
88
|
+
is_back_to_zero = True
|
|
89
|
+
send_thread.join()
|
|
90
|
+
else:
|
|
91
|
+
last_throttle_value = 0
|
|
92
|
+
msigs = get_eav24_msigs(dbc, last_throttle_value, 1, 0, 0)
|
|
93
|
+
send_thread.join()
|
|
94
|
+
send_thread = threading.Thread(target=send_eav24_can_signals, args=(bus, msigs, send_rate, duration))
|
|
95
|
+
send_thread.start()
|
|
96
|
+
last_throttle_time = time.time()
|
|
97
|
+
|
|
98
|
+
# Plot results
|
|
99
|
+
avg_delay = statistics.mean(delays)
|
|
100
|
+
print('avg delay {}, min delay {}, max dealy {}'.format(avg_delay, min(delays), max(delays)))
|
|
101
|
+
|
|
102
|
+
if save_report_as != '':
|
|
103
|
+
print('saving report to {}'.format(save_report_as))
|
|
104
|
+
report = {
|
|
105
|
+
'average_delay': avg_delay,
|
|
106
|
+
'min_delay': min(delays),
|
|
107
|
+
'max_delay': max(delays),
|
|
108
|
+
'num_samples': nsamples
|
|
109
|
+
}
|
|
110
|
+
with open(save_report_as, 'w', encoding='utf-8') as f:
|
|
111
|
+
json.dump(report, f, ensure_ascii=False, indent=4)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def echo_can(can_names, dbcs, duration, isolate, do_rates, save_report_as):
|
|
115
|
+
start_time = time.time()
|
|
116
|
+
report = {}
|
|
117
|
+
rates = {}
|
|
118
|
+
print_interval = 1.0
|
|
119
|
+
last_print = start_time
|
|
120
|
+
|
|
121
|
+
jobs = []
|
|
122
|
+
print_lock = threading.Lock()
|
|
123
|
+
for n in can_names:
|
|
124
|
+
echo_thread = threading.Thread(target=echo_can_job, args=(n, dbcs, duration, isolate, do_rates, rates, print_lock))
|
|
125
|
+
echo_thread.start()
|
|
126
|
+
jobs.append(echo_thread)
|
|
127
|
+
|
|
128
|
+
while time.time() - start_time < duration:
|
|
129
|
+
t = time.time()
|
|
130
|
+
if do_rates and t - last_print > print_interval:
|
|
131
|
+
last_print = t
|
|
132
|
+
for r in rates:
|
|
133
|
+
print('{} rate: {}hz ({} samples)'.format(r, 1.0 / rates[r]['rate'], rates[r]['ct']))
|
|
134
|
+
print('=' * 15)
|
|
135
|
+
|
|
136
|
+
for j in jobs:
|
|
137
|
+
j.join()
|
|
138
|
+
|
|
139
|
+
if do_rates and save_report_as != '':
|
|
140
|
+
print('saving report to {}'.format(save_report_as))
|
|
141
|
+
with open(save_report_as, 'w', encoding='utf-8') as f:
|
|
142
|
+
json.dump(rates, f, ensure_ascii=False, indent=4)
|
|
143
|
+
|
|
144
|
+
def echo_can_job(can_name, dbcs, duration, isolate, do_rates, out_rate_data, print_lock):
|
|
145
|
+
start_time = time.time()
|
|
146
|
+
with can.interface.Bus(can_name, bustype='socketcan') as bus:
|
|
147
|
+
while time.time() - start_time < duration:
|
|
148
|
+
message = bus.recv()
|
|
149
|
+
if message is not None:
|
|
150
|
+
for db in dbcs:
|
|
151
|
+
decoded = decode_can_message(db, message)
|
|
152
|
+
if decoded is not None and (len(isolate) == 0 or decoded['name'] in isolate):
|
|
153
|
+
update_can_rate_stats(decoded, out_rate_data, start_time)
|
|
154
|
+
if not do_rates and print_lock.acquire(True):
|
|
155
|
+
print(decoded)
|
|
156
|
+
print_lock.release()
|
|
157
|
+
|
|
158
|
+
def decode_can_message(dbc, message):
|
|
159
|
+
try:
|
|
160
|
+
decoded_message = dbc.decode_message(message.arbitration_id, message.data)
|
|
161
|
+
message_name = dbc.get_message_by_frame_id(message.arbitration_id).name
|
|
162
|
+
timestamp = datetime.datetime.now().isoformat()
|
|
163
|
+
return {'timestamp': timestamp, 'name': message_name, 'data': decoded_message}
|
|
164
|
+
except KeyError:
|
|
165
|
+
return None
|
|
166
|
+
|
|
167
|
+
def update_can_rate_stats(message, rates, start_time):
|
|
168
|
+
if not message['name'] in rates:
|
|
169
|
+
rates[message['name']] = {
|
|
170
|
+
'prev_t': start_time,
|
|
171
|
+
'rate': time.time() - start_time,
|
|
172
|
+
'ct': 0,
|
|
173
|
+
'min': 100000000,
|
|
174
|
+
'max': 0.0000001
|
|
175
|
+
}
|
|
176
|
+
r = rates[message['name']]['rate']
|
|
177
|
+
t = rates[message['name']]['prev_t']
|
|
178
|
+
ct = rates[message['name']]['ct'] + 1
|
|
179
|
+
dt = time.time() - t
|
|
180
|
+
rate_diff = dt - r
|
|
181
|
+
rates[message['name']]['rate'] = r + (1.0 / ct) * rate_diff
|
|
182
|
+
rates[message['name']]['ct'] = ct
|
|
183
|
+
rates[message['name']]['prev_t'] = time.time()
|
|
184
|
+
|
|
185
|
+
this_rate = 1.0 / dt
|
|
186
|
+
if this_rate > rates[message['name']]['max']:
|
|
187
|
+
rates[message['name']]['max'] = this_rate
|
|
188
|
+
elif this_rate < rates[message['name']]['min']:
|
|
189
|
+
rates[message['name']]['min'] = this_rate
|
|
190
|
+
|
avrs/cfg.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import shutil
|
|
4
|
+
|
|
5
|
+
def get_cfg_dir(cli_name):
|
|
6
|
+
return os.path.join(os.environ['HOME'], '.config', cli_name)
|
|
7
|
+
|
|
8
|
+
def get_cfg_file(cli_name):
|
|
9
|
+
return os.path.join(get_cfg_dir(cli_name), 'config.json')
|
|
10
|
+
|
|
11
|
+
def load_cfg(cli_name):
|
|
12
|
+
cfg_dir = get_cfg_dir(cli_name)
|
|
13
|
+
if not os.path.exists(cfg_dir):
|
|
14
|
+
os.makedirs(cfg_dir)
|
|
15
|
+
|
|
16
|
+
cfg_path = get_cfg_file(cli_name)
|
|
17
|
+
cfg = {}
|
|
18
|
+
|
|
19
|
+
if os.path.exists(cfg_path):
|
|
20
|
+
with open(cfg_path, 'r', encoding='utf-8') as f:
|
|
21
|
+
cfg = json.load(f)
|
|
22
|
+
return cfg
|
|
23
|
+
|
|
24
|
+
def save_cfg(cli_name, cfg):
|
|
25
|
+
cfg_path = get_cfg_file(cli_name)
|
|
26
|
+
with open(cfg_path, 'w', encoding='utf-8') as f:
|
|
27
|
+
json.dump(cfg, f, ensure_ascii=False, indent=4)
|
|
28
|
+
|
|
29
|
+
# Save a file to be re-used later to a cached location
|
|
30
|
+
def add_cached_file(cli_name, category, file_to_cache, overwrite_ok):
|
|
31
|
+
if not os.path.exists(file_to_cache):
|
|
32
|
+
return (False, '{} is not a valid file'.format(file_to_cache))
|
|
33
|
+
cfg = load_cfg(cli_name)
|
|
34
|
+
if '__cached_files__' not in cfg:
|
|
35
|
+
cfg['__cached_files__'] = {}
|
|
36
|
+
if category not in cfg['__cached_files__']:
|
|
37
|
+
cfg['__cached_files__'][category] = []
|
|
38
|
+
file_to_cache_name = os.path.basename(file_to_cache)
|
|
39
|
+
cfg['__cached_files__'][category].append(file_to_cache_name)
|
|
40
|
+
cat_path = os.path.join(get_cfg_dir(cli_name), category)
|
|
41
|
+
if not os.path.exists(cat_path):
|
|
42
|
+
os.makedirs(cat_path)
|
|
43
|
+
cache_path = os.path.join(cat_path, file_to_cache_name)
|
|
44
|
+
if os.path.isfile(cache_path) and not overwrite_ok:
|
|
45
|
+
return (False, '{} already exists and overwrite not specified as ok'.format(cache_path))
|
|
46
|
+
shutil.copyfile(file_to_cache, cache_path)
|
|
47
|
+
save_cfg(cli_name, cfg)
|
|
48
|
+
return (True, '{} cached to {}'.format(file_to_cache, cache_path))
|
|
49
|
+
|
|
50
|
+
# Get a file previously cached
|
|
51
|
+
def get_cached_file(cli_name, category, file_to_get):
|
|
52
|
+
cfg = load_cfg(cli_name)
|
|
53
|
+
if '__cached_files__' not in cfg:
|
|
54
|
+
return (False, 'no cached files')
|
|
55
|
+
if category not in cfg['__cached_files__']:
|
|
56
|
+
return (False, 'cached file {} not found'.format(file_to_get))
|
|
57
|
+
cache_path = os.path.join(get_cfg_dir(cli_name), category, file_to_get)
|
|
58
|
+
cf = cfg['__cached_files__'][category]
|
|
59
|
+
# Check by index
|
|
60
|
+
try:
|
|
61
|
+
file_index = int(file_to_get)
|
|
62
|
+
if file_index > -1 and file_index < len(cf):
|
|
63
|
+
cache_path = os.path.join(get_cfg_dir(cli_name), category, cf[file_index])
|
|
64
|
+
else:
|
|
65
|
+
return (False, '{} is not a valid file index'.format(file_index))
|
|
66
|
+
except Exception as e:
|
|
67
|
+
pass
|
|
68
|
+
if not os.path.exists(cache_path):
|
|
69
|
+
return (False, 'failed to get cached file at {}'.format(cache_path))
|
|
70
|
+
return (True, cache_path)
|
|
71
|
+
|
|
72
|
+
def get_cached_file_list(cli_name, category):
|
|
73
|
+
cfg = load_cfg(cli_name)
|
|
74
|
+
if '__cached_files__' not in cfg:
|
|
75
|
+
return []
|
|
76
|
+
if category not in cfg['__cached_files__']:
|
|
77
|
+
return []
|
|
78
|
+
return cfg['__cached_files__'][category]
|
avrs/launcher.py
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import stat
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
5
|
+
import http.client
|
|
6
|
+
import boto3
|
|
7
|
+
import sys
|
|
8
|
+
import shutil
|
|
9
|
+
from avrs.cfg import *
|
|
10
|
+
from avrs.launcher_util import *
|
|
11
|
+
|
|
12
|
+
class AvrsLauncher:
|
|
13
|
+
def __init__(self, parent_parser, cfg):
|
|
14
|
+
self.cfg = cfg
|
|
15
|
+
self.logger = logging.getLogger('avrs')
|
|
16
|
+
provision_parser = parent_parser.add_parser(
|
|
17
|
+
'launcher',
|
|
18
|
+
help='launcher operations, such as license registration or updating a sim install\n\n')
|
|
19
|
+
sps = provision_parser.add_subparsers(required=True, help='launcher options')
|
|
20
|
+
|
|
21
|
+
register_license_psr = sps.add_parser(
|
|
22
|
+
'register-license',
|
|
23
|
+
help='registers a user license, allowing certain functionaility')
|
|
24
|
+
register_license_psr.add_argument(
|
|
25
|
+
'license_path',
|
|
26
|
+
help='the path to the license file to register')
|
|
27
|
+
register_license_psr.set_defaults(func=self.register_license)
|
|
28
|
+
|
|
29
|
+
license_status_psr = sps.add_parser(
|
|
30
|
+
'license-status',
|
|
31
|
+
help='shows information related to a user license')
|
|
32
|
+
license_status_psr.set_defaults(func=self.license_status)
|
|
33
|
+
|
|
34
|
+
get_latest_psr = sps.add_parser(
|
|
35
|
+
'get-latest-sim-version',
|
|
36
|
+
help='ask the build info api for the latest sim version')
|
|
37
|
+
get_latest_psr.add_argument("variant", help="which variant to get the latest verison of")
|
|
38
|
+
get_latest_psr.set_defaults(func=self.get_latest_sim_version)
|
|
39
|
+
|
|
40
|
+
get_variants_psr = sps.add_parser(
|
|
41
|
+
'list-variants',
|
|
42
|
+
help='lists the available variants of the simulator that can be downloaded')
|
|
43
|
+
get_variants_psr.set_defaults(func=self.get_variants)
|
|
44
|
+
|
|
45
|
+
download_sim_psr = sps.add_parser('download-simulator', help='download the simulator')
|
|
46
|
+
download_sim_psr.add_argument('variant', help='which variant of the simulator to download (eg, \"a2rl-iron\" or \"a2rl-humble\")')
|
|
47
|
+
download_sim_psr.add_argument('install_path', help='path to install the simulator')
|
|
48
|
+
download_sim_psr.add_argument('--target-version', default='', help='specify a version other than the most recent to download')
|
|
49
|
+
download_sim_psr.add_argument(
|
|
50
|
+
'--copy-saved-from',
|
|
51
|
+
default='',
|
|
52
|
+
help='path to an existing installation from which to copy saved information')
|
|
53
|
+
download_sim_psr.add_argument(
|
|
54
|
+
'--update-existing',
|
|
55
|
+
action='store_true',
|
|
56
|
+
help='indicates that the user understands that they are updating an existing installation')
|
|
57
|
+
download_sim_psr.set_defaults(func=self.download_simulator)
|
|
58
|
+
|
|
59
|
+
def register_license(self, args):
|
|
60
|
+
print('Trying to Register License File: {}'.format(args.license_path))
|
|
61
|
+
|
|
62
|
+
# Load and validate provided license file
|
|
63
|
+
license_ok, license_status, license = validate_license_file(args.license_path)
|
|
64
|
+
if not license_ok:
|
|
65
|
+
print('Error Reading License File: {}'.format(license_status))
|
|
66
|
+
return
|
|
67
|
+
|
|
68
|
+
# Cache license info in config
|
|
69
|
+
license_name = os.path.basename(args.license_path)
|
|
70
|
+
self.cfg['license'] = {
|
|
71
|
+
'filename': os.path.basename(license_name),
|
|
72
|
+
'data': license
|
|
73
|
+
}
|
|
74
|
+
save_cfg('avrs', self.cfg)
|
|
75
|
+
print('License Registration Success: {}'.format(self.cfg['license']['filename']))
|
|
76
|
+
|
|
77
|
+
# Try to exchange license info for download keys
|
|
78
|
+
print('Retrieving Launcher Download Keys...')
|
|
79
|
+
(dl_keys_ok, dl_keys_status, self.cfg) = try_get_launcher_download_keys(self.cfg)
|
|
80
|
+
if not dl_keys_ok:
|
|
81
|
+
print('Error Getting Launcher Download Keys: {}'.format(dl_keys_status))
|
|
82
|
+
return
|
|
83
|
+
save_cfg('avrs', self.cfg)
|
|
84
|
+
print('Download Key Retrieval Success')
|
|
85
|
+
|
|
86
|
+
def license_status(self, args):
|
|
87
|
+
status = get_launcher_license_status_string(self.cfg)
|
|
88
|
+
print('Launcher License Status: {}'.format(status))
|
|
89
|
+
|
|
90
|
+
def get_available_sim_versions(self, args):
|
|
91
|
+
pass
|
|
92
|
+
|
|
93
|
+
# query something to find out what versions of the sim we can download
|
|
94
|
+
|
|
95
|
+
def get_variants(self, args):
|
|
96
|
+
if 'license' not in self.cfg:
|
|
97
|
+
print('no license has been registered\n')
|
|
98
|
+
return
|
|
99
|
+
|
|
100
|
+
(dl_keys_ok, dl_keys_status, self.cfg) = try_get_launcher_download_keys(self.cfg)
|
|
101
|
+
if not dl_keys_ok:
|
|
102
|
+
print('Error Getting Launcher Download Keys: {}'.format(dl_keys_status))
|
|
103
|
+
return
|
|
104
|
+
save_cfg('avrs', self.cfg)
|
|
105
|
+
print('{}'.format(self.cfg['variants']))
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def get_latest_sim_version(self, args):
|
|
109
|
+
self.logger.info('getting latest sim version')
|
|
110
|
+
# Validate status of download keys
|
|
111
|
+
dl_keys_ok, dl_keys_status = has_launcher_download_keys(self.cfg)
|
|
112
|
+
if not dl_keys_ok:
|
|
113
|
+
print('Launcher Download Keys Error: {}'.format(dl_keys_status))
|
|
114
|
+
return
|
|
115
|
+
|
|
116
|
+
# Check if variant is valid (for backwards compatibility, we still proceed even if invalid)
|
|
117
|
+
variant_is_invalid = False
|
|
118
|
+
if args.variant not in ["staged", "feature"]:
|
|
119
|
+
# Ensure variants are loaded
|
|
120
|
+
if 'variants' not in self.cfg:
|
|
121
|
+
(dl_keys_ok, dl_keys_status, self.cfg) = try_get_launcher_download_keys(self.cfg)
|
|
122
|
+
if not dl_keys_ok:
|
|
123
|
+
# If we can't get variants, proceed anyway for backwards compatibility
|
|
124
|
+
pass
|
|
125
|
+
if 'variants' in self.cfg and args.variant not in self.cfg['variants']:
|
|
126
|
+
variant_is_invalid = True
|
|
127
|
+
# Write warning to stderr so it doesn't interfere with scripts parsing stdout
|
|
128
|
+
sys.stderr.write('Warning: "{}" is not a known variant. Available variants: {}\n'.format(
|
|
129
|
+
args.variant, self.cfg['variants']))
|
|
130
|
+
|
|
131
|
+
variant_to_query = "autoverse" if args.variant in ["staged", "feature"] else args.variant
|
|
132
|
+
|
|
133
|
+
# Get latest build info from API
|
|
134
|
+
build_info_ok, build_info_status, latest_version, staged_version, build_info = get_launcher_build_info(
|
|
135
|
+
self.cfg, variant_to_query)
|
|
136
|
+
if not build_info_ok:
|
|
137
|
+
print('Error Getting Latest Version Info: {}'.format(build_info_status))
|
|
138
|
+
return
|
|
139
|
+
|
|
140
|
+
if args.variant == "staged":
|
|
141
|
+
print('{}'.format(staged_version))
|
|
142
|
+
elif args.variant == "feature":
|
|
143
|
+
feature_info = build_info.get('feature', {})
|
|
144
|
+
if isinstance(feature_info, str):
|
|
145
|
+
try:
|
|
146
|
+
feature_info = json.loads(feature_info)
|
|
147
|
+
except json.JSONDecodeError:
|
|
148
|
+
pass
|
|
149
|
+
print('{}'.format(json.dumps(feature_info)))
|
|
150
|
+
else:
|
|
151
|
+
print('{}'.format(latest_version))
|
|
152
|
+
if variant_is_invalid:
|
|
153
|
+
# Explain that the output is the default/prod variant version, not the requested variant
|
|
154
|
+
sys.stderr.write('Note: The version shown above is the production version of the default variant, not "{}"\n'.format(
|
|
155
|
+
args.variant))
|
|
156
|
+
|
|
157
|
+
def download_simulator(self, args):
|
|
158
|
+
|
|
159
|
+
# update variants before each download. also updates download keys
|
|
160
|
+
print('Updating Variants...')
|
|
161
|
+
self.get_variants(args)
|
|
162
|
+
|
|
163
|
+
if args.variant not in self.cfg['variants']:
|
|
164
|
+
print('\"{}\" is not a known variant, try one of: {}'.format(
|
|
165
|
+
args.variant, self.cfg['variants']))
|
|
166
|
+
return
|
|
167
|
+
|
|
168
|
+
file_path = args.install_path
|
|
169
|
+
if not os.path.exists(file_path):
|
|
170
|
+
print('Cannot Install Simulator at: {} (Invalid Path, Specify a Directory)'.format(file_path))
|
|
171
|
+
return
|
|
172
|
+
|
|
173
|
+
# Validate status of download keys
|
|
174
|
+
dl_keys_ok, dl_keys_status = has_launcher_download_keys(self.cfg)
|
|
175
|
+
if not dl_keys_ok:
|
|
176
|
+
print('Launcher Download Keys Error: {}'.format(dl_keys_status))
|
|
177
|
+
return
|
|
178
|
+
|
|
179
|
+
# Get latest build info from API
|
|
180
|
+
build_info_ok, build_info_status, latest_version, staged_version, _build_info = get_launcher_build_info(
|
|
181
|
+
self.cfg, args.variant)
|
|
182
|
+
if not build_info_ok:
|
|
183
|
+
print('Error Getting Latest Version Info: {}'.format(build_info_status))
|
|
184
|
+
return
|
|
185
|
+
|
|
186
|
+
# If we want to copy saved info from another installation
|
|
187
|
+
copy_saved = False
|
|
188
|
+
copy_saved_cache = ''
|
|
189
|
+
if args.copy_saved_from != '':
|
|
190
|
+
if not is_installed_sim(args.copy_saved_from):
|
|
191
|
+
print('The Path: {} Is not an Existing Installation. Cannot Copy Saved'.format(args.copy_saved_from))
|
|
192
|
+
return
|
|
193
|
+
else:
|
|
194
|
+
copy_saved = True
|
|
195
|
+
|
|
196
|
+
if copy_saved:
|
|
197
|
+
print('Caching Saved from Existing Installation at: {}'.format(args.copy_saved_from))
|
|
198
|
+
copy_from_saved_dir = os.path.join(args.copy_saved_from, 'Linux', 'Autoverse', 'Saved')
|
|
199
|
+
copy_saved_cache = os.path.join(args.install_path, 'autoverse-saved-cache')
|
|
200
|
+
shutil.copytree(copy_from_saved_dir, copy_saved_cache)
|
|
201
|
+
|
|
202
|
+
target_version = latest_version
|
|
203
|
+
if args.target_version == 'staged':
|
|
204
|
+
target_version = staged_version
|
|
205
|
+
print('attempting to download staged version: {}'.format(target_version))
|
|
206
|
+
elif args.target_version != '':
|
|
207
|
+
target_version = args.target_version
|
|
208
|
+
print('attempting to download specified version: {}'.format(target_version))
|
|
209
|
+
|
|
210
|
+
package_zip_name = 'autoverse-linux-{}.zip'.format(target_version)
|
|
211
|
+
package_name = 'autoverse-linux'
|
|
212
|
+
if target_version == 'feature':
|
|
213
|
+
args.variant = 'feature'
|
|
214
|
+
bucket_path = '{}/{}'.format(args.variant, package_zip_name)
|
|
215
|
+
dl_path = os.path.join(args.install_path, package_zip_name)
|
|
216
|
+
unzip_path = os.path.join(args.install_path, package_name)
|
|
217
|
+
|
|
218
|
+
if is_installed_sim(unzip_path) and not args.update_existing:
|
|
219
|
+
print('''
|
|
220
|
+
Downloading at {} will update an existing installation and override its saved information.
|
|
221
|
+
make sure you have backups of any configuration or use the --copy-saved-from option.
|
|
222
|
+
If you are sure, re-run with the --update-existing flag
|
|
223
|
+
'''.format(unzip_path))
|
|
224
|
+
return
|
|
225
|
+
|
|
226
|
+
if not is_installed_sim(unzip_path):
|
|
227
|
+
if not 'installs' in self.cfg:
|
|
228
|
+
self.cfg['installs'] = []
|
|
229
|
+
self.cfg['installs'].append(unzip_path)
|
|
230
|
+
save_cfg('avrs', self.cfg)
|
|
231
|
+
|
|
232
|
+
print('Downloading {} to {}. This May Take Several Minutes Depending on Connection Speed'.format(bucket_path, dl_path))
|
|
233
|
+
download_simulator_archive(self.cfg, bucket_path, dl_path)
|
|
234
|
+
|
|
235
|
+
print('Extracting {} to {}'.format(dl_path, unzip_path))
|
|
236
|
+
shutil.unpack_archive(dl_path, unzip_path)
|
|
237
|
+
|
|
238
|
+
if copy_saved:
|
|
239
|
+
print('Migrating Saved Files')
|
|
240
|
+
shutil.copytree(copy_saved_cache, os.path.join(unzip_path, 'Linux', 'Autoverse', 'Saved'), dirs_exist_ok=True)
|
|
241
|
+
shutil.rmtree(copy_saved_cache)
|
|
242
|
+
|
|
243
|
+
# Install license if missing
|
|
244
|
+
if not copy_saved:
|
|
245
|
+
print('Installing Registered License: {}'.format(self.cfg['license']['filename']))
|
|
246
|
+
license_install_path = os.path.join(unzip_path, 'Linux', 'Autoverse', 'Saved', self.cfg['license']['filename'])
|
|
247
|
+
with open(license_install_path, 'w', encoding='utf-8') as f:
|
|
248
|
+
json.dump(self.cfg['license']['data'], f, ensure_ascii=False, indent=4)
|
|
249
|
+
|
|
250
|
+
# Make Autovers.sh executable
|
|
251
|
+
autoverse_exe = os.path.join(unzip_path, 'Linux', 'Autoverse.sh')
|
|
252
|
+
st = os.stat(autoverse_exe)
|
|
253
|
+
os.chmod(autoverse_exe, st.st_mode | stat.S_IEXEC)
|
|
254
|
+
|
|
255
|
+
print('Cleaning up')
|
|
256
|
+
os.remove(dl_path)
|