-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathameba_arduino_release_package_maker.py
424 lines (334 loc) · 15.8 KB
/
ameba_arduino_release_package_maker.py
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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
#import requests
import os
#import shutil
import time
#from datetime import date
#import openpyxl
import sys
#import datetime
import json
SDK_info_array = ["", "", "", "", "", "", ""]
Package_name = ["TEMP.tar.gz", ""]
def string_search_and_replace(text, substring, replacement, case_sensitive=True):
"""
Searches for a substring in a string and replaces all occurrences with a replacement string.
Args:
text: The string to search in.
substring: The substring to search for.
replacement: The string to replace the substring with.
case_sensitive: Whether to perform a case-sensitive search (default: True).
Returns:
The modified string with all occurrences of the substring replaced.
"""
if not case_sensitive:
text = text.lower()
substring = substring.lower()
new_text = text
if substring not in text:
raise ValueError("release type and branch not match")
index = new_text.find(substring)
new_text = new_text[:index] + replacement + new_text[index + len(substring):]
return new_text
def update_tag(release_type, text, substring="QC", remove="-"):
if release_type == "E" or release_type == "R":
if substring not in text:
index = 5
new_value = str(int(text[index]) + 1)
return text[1:index] + new_value + text[index + 1:]
else:
index_substring = text.find(substring)
index_remove = text.find(remove)
return text[1:index_remove]
else:
raise ValueError("no match branch")
def remove_left_of_second_data(text, second_data="/"):
"""
Finds the second occurrence of second_data from the right and removes all data to the left of it.
Args:
text: The string to modify.
second_data: The data to search for (default: "A").
Returns:
The modified string with data to the left of the second occurrence of second_data removed.
"""
# Reverse the string
reversed_text = text[::-1]
# Find the first two occurrences of second_data
first_index = reversed_text.find(second_data)
second_index = reversed_text.find(second_data, first_index + 1)
# Check if the second occurrence exists
if second_index == -1:
return text # Return original text if the second instance is not found
# Calculate the index to keep in the original string
index_to_keep = len(text) - second_index - len(second_data)
# Return the portion of the string to the right of the second data A
return text[index_to_keep:]
def remove_after_word(text, word="raw"):
"""
Removes all data from the right of a specified word in a string, including the word itself.
Args:
text: The string to modify.
word: The word to find and remove data after (case-sensitive).
Returns:
The modified string with data after the specified word removed.
"""
# Find the index of the word
index = text.find(word)
# Return the portion of the string up to the index of the word + its length
if index != -1:
return text[:index + len(word)] + "/" # Include the length of the word
else:
return text + "/"
def save_json_to_text(json_file, text_file, start_line, end_line):
"""
Saves lines from a JSON file to a text file, line by line, preserving indentation.
Handles empty lines and varying indentation levels.
Args:
json_file (str): Path to the JSON file.
text_file (str): Path to the output text file.
start_line (int): Line number to start from (1-based indexing).
end_line (int): Line number to end at (inclusive, 1-based indexing).
Raises:
ValueError: If start or end line is invalid.
IOError: If there's an error reading or writing files.
"""
with open(json_file, 'r') as f:
lines = f.readlines()
if start_line < 1 or start_line > len(lines):
raise ValueError("Invalid start line number: {}".format(start_line))
if end_line < start_line or end_line > len(lines):
raise ValueError("Invalid end line number: {}".format(end_line))
with open(text_file, 'w') as f:
current_indent = 0 # Start with no indentation
for line in lines[start_line - 1:end_line]:
if line.strip(): # Handle non-empty lines
# Calculate actual indentation based on spaces
indent = len(line) - len(line.lstrip())
f.write(' ' * indent + line.strip() + '\n')
current_indent = indent # Update for subsequent lines
else: # Handle empty lines
f.write('\n') # Preserve empty lines if needed
def insert_text_into_json(target_file, file_to_insert, line_number):
"""Inserts data from a file into a JSON file above the specified line number, line by line.
Args:
target_file (str): Path to the target JSON file.
file_to_insert (str): Path to the file containing the data to insert.
line_number (int): The line number above which to insert the data (1-based indexing).
Raises:
ValueError: If the line number is invalid or the target file is empty.
IOError: If there's an error reading or writing the files.
"""
with open(target_file, 'r+') as f:
lines = f.readlines()
if line_number < 1 or line_number > len(lines):
raise ValueError("Invalid line number: {}".format(line_number))
with open(file_to_insert, 'r') as insert_file:
insert_lines = insert_file.readlines()
# Preserve indentation of the target file
indent_level = lines[line_number - 1].count(' ')
# Insert each line with proper indentation
for line in insert_lines:
insert_line = ' ' * indent_level + line.rstrip('\n') + '\n'
lines.insert(line_number - 1, insert_line)
line_number += 1 # Adjust for added lines
# Rewrite the target file with the updated content
f.seek(0)
f.truncate()
f.writelines(lines)
def replace_spaces_with_tabs_specific_lines(input_file, output_file, lines_to_replace, num_spaces=1, replace_leading_spaces=True):
"""
Replaces spaces with tabs in specific lines of a text file, keeping spaces in other lines.
Args:
input_file (str): Path to the input text file.
output_file (str): Path to the output text file.
lines_to_replace (list[int]): List of line numbers to replace spaces with tabs (1-based indexing).
num_spaces (int, optional): Number of spaces to replace with one tab. Defaults to 4.
replace_leading_spaces (bool, optional): Whether to replace leading spaces. Defaults to False.
"""
with open(input_file, 'r') as fin, open(output_file, 'w') as fout:
line_number = 0
for line in fin:
line_number += 1
# Convert line_number to a list or set before checking membership
if line_number in [lines_to_replace]: # Use a list containing only line_number
if replace_leading_spaces:
# Replace all spaces in specified lines
new_line = line.replace(' ', '\t', num_spaces)
else:
# Replace non-leading spaces in specified lines
new_line = line.lstrip().replace(' ', '\t', num_spaces)
else:
# Keep spaces in other lines
new_line = line
fout.write(new_line)
def replace_line_data(input_file, output_file, target_line_number, new_data, match_whole_line=True):
"""
Replaces data in a specific line of a text file.
Args:
input_file (str): Path to the input text file.
output_file (str): Path to the output text file (optional).
target_line_number (int): The line number to replace (1-based indexing).
new_data (str): The replacement data.
match_whole_line (bool, optional): Whether to match the entire line for replacement.
Defaults to False.
Raises:
ValueError: If the target line number is invalid or the file cannot be read/written.
"""
try:
with open(input_file, 'r') as fin:
lines = fin.readlines()
if target_line_number < 1 or target_line_number > len(lines):
raise ValueError("Invalid target line number:", target_line_number)
modified_line = lines[target_line_number - 1]
if match_whole_line:
new_line = new_data + '\n' # Add newline if entire line is replaced
else:
# Handle potential index errors and edge cases for partial replacements
try:
start_index = modified_line.index(new_data) # Use new_data for the search
end_index = start_index + len(new_data)
new_line = modified_line[:start_index] + new_data + modified_line[end_index:]
except ValueError:
#print("Warning: Data not found on that line. Skipping replacement.")
new_line = modified_line
lines[target_line_number - 1] = new_line
with open(output_file if output_file else input_file, 'w') as fout:
fout.writelines(lines)
#print(f"Line {target_line_number} replaced successfully!")
except (IOError, ValueError) as e:
print(f"Error: {e}")
# get tool tag name
def find_all_matches_and_extract_suffixes(folder_path, prefix, suffix):
matches = []
for root, dirs, files in os.walk(folder_path):
for file_name in files:
if file_name.startswith(prefix) and file_name.endswith(suffix):
# Extract part after prefix
result = file_name[len(prefix):]
# Remove suffix
if result.endswith(suffix):
result = result[:-len(suffix)]
matches.append(result)
return matches
# compare tool tag name, "A.B.C" or "A.B.C.D"
def compare_and_keep_largest(data_list):
def parse_version(version):
return [int(part) for part in version.split('.')]
while len(data_list) > 1:
# Compare by each component
max_a = max(parse_version(v)[0] for v in data_list)
data_list = [v for v in data_list if parse_version(v)[0] == max_a]
if len(data_list) == 1:
break
max_b = max(parse_version(v)[1] for v in data_list)
data_list = [v for v in data_list if parse_version(v)[1] == max_b]
if len(data_list) == 1:
break
max_c = max(parse_version(v)[2] for v in data_list)
data_list = [v for v in data_list if parse_version(v)[2] == max_c]
if len(data_list) == 1:
break
if len(parse_version(data_list[0])) == 4:
max_d = max(parse_version(v)[3] for v in data_list if len(parse_version(v)) == 4)
data_list = [v for v in data_list if len(parse_version(v)) == 4 and parse_version(v)[3] == max_d]
break
return data_list[0] if data_list else None
def text_update_release_info(temp1_file_path, temp2_file_path, SDK_info_array):
SDK_repo = SDK_info_array[0]
SDK_release_type = SDK_info_array[1]
SDK_tag = SDK_info_array[2]
SDK_sha= SDK_info_array[3]
SDK_size = SDK_info_array[4]
SDK_https_raw = remove_after_word(SDK_info_array[5])
# print(http_raw)
if SDK_release_type == "E":
today_date = time.strftime("%Y%m%d")
SDK_tag = SDK_tag + "-build" + today_date
SDK_Repo_branch = "dev"
elif SDK_release_type == "R":
if SDK_info_array[6] == "main":
SDK_Repo_branch = "main"
elif SDK_info_array[6] == "master":
SDK_Repo_branch = "master"
else:
raise ValueError("wrong branch name main/master")
else:
raise ValueError("no match branch")
# 4 9 10 11 12
# 21 26
# 31
# 36
replace_line_data(temp1_file_path, temp2_file_path, 4, " \"version\": \"" + SDK_tag + "\",")
replace_line_data(temp2_file_path, temp1_file_path, 9, " \"url\": \"" +SDK_https_raw + SDK_Repo_branch + "/Arduino_package/release/" + SDK_repo + "-" + SDK_tag + ".tar.gz\",")
replace_line_data(temp1_file_path, temp2_file_path, 10, " \"archiveFileName\": \"" + SDK_repo + "-" + SDK_tag + ".tar.gz\",")
replace_line_data(temp2_file_path, temp1_file_path, 11, " \"checksum\": \"SHA-256:" + SDK_sha + "\",")
replace_line_data(temp1_file_path, temp2_file_path, 12, " \"size\": \"" + SDK_size + "\",")
temp_array = find_all_matches_and_extract_suffixes("./", "ameba_pro2_tools_windows-", ".tar.gz")
TOOL_tag = compare_and_keep_largest(temp_array)
replace_line_data(temp2_file_path, temp1_file_path, 31, " \"version\": \"" + TOOL_tag + "\"")
# back to temp2
replace_line_data(temp1_file_path, temp2_file_path, 12, " \"size\": \"" + SDK_size + "\",")
Package_name[0] = "./Arduino_package/release/" + Package_name[0]
Package_name[1] = "./Arduino_package/release/" + SDK_repo + "-" + SDK_tag + ".tar.gz"
def json_copy_release_info(json_file_path, temp1_file_path, temp2_file_path, SDK_info_array):
save_json_to_text(json_file_path, temp1_file_path, 13, 51)
replace_spaces_with_tabs_specific_lines(temp1_file_path, temp2_file_path, 1)
replace_spaces_with_tabs_specific_lines(temp2_file_path, temp1_file_path, 1)
text_update_release_info(temp1_file_path, temp2_file_path, SDK_info_array)
insert_text_into_json(json_file_path, temp2_file_path, 13)
def remove_file(remove_file_path):
# if os.path.exists('./Arduino_package/temp.txt'):
# os.remove('./Arduino_package/temp.txt')
if os.path.exists(remove_file_path):
os.remove(remove_file_path)
def rename_file(old_path, new_path):
"""
Renames a file from the old path to the new path.
Args:
old_path: The current path of the file.
new_path: The desired new path of the file.
Raises:
OSError: If renaming fails due to various reasons.
"""
try:
os.rename(old_path, new_path)
except OSError as e:
raise OSError(f"Failed to rename file: {e}") from e
def main(input_1, input_2, input_3, input_4, input_5, input_6, input_7):
print('......Running Python!!!')
# print(input_1) # input_1 REPO_NAME
# print(input_2) # input_2 E / R
# print(input_3) # input_3 LAST_TAG
# print(input_4) # input_4 PACKAGE_SHA
# print(input_5) # input_5 PACKAGE_SIZE
# print(input_6) # input_6 JSON_LINK_DEV / JSON_LINK_MAIN
# print(input_7) # input_7 RRLEASE_BRANCH_NAME
if input_2 == "E":
string_search_and_replace(input_6, "dev", "dev")
elif input_2 == "R":
string_search_and_replace(input_6, input_7, input_7)
else:
raise ValueError("no match branch")
SDK_info_array[0] = input_1 # ameba_pro2
SDK_info_array[1] = input_2 # E / R
input_3 = update_tag(input_2, input_3)
SDK_info_array[2] = input_3 # ${{ env.LAST_TAG }}
SDK_info_array[3] = input_4 # ${{ env.PACKAGE_SHA }}
SDK_info_array[4] = input_5 # ${{ env.PACKAGE_SIZE }}
input_6 = string_search_and_replace(input_6, "blob", "raw")
SDK_info_array[5] = input_6 # json url
SDK_info_array[6] = input_7 # main/master
json_file_name = "." + remove_left_of_second_data(input_6)
# print(json_file_name)
open('./temp1.txt', 'w').close() #Create the file
open('./temp2.txt', 'w').close() #Create the file
json_file_path = os.path.abspath(json_file_name)
temp1_file_path = os.path.abspath('./temp1.txt')
temp2_file_path = os.path.abspath('./temp2.txt')
json_copy_release_info(json_file_path, temp1_file_path, temp2_file_path, SDK_info_array)
remove_file(temp1_file_path)
remove_file(temp2_file_path)
rename_file(Package_name[0], Package_name[1])
print('......Done')
if __name__ == "__main__":
# main()
main(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6], sys.argv[7])