[WS] Convert CRLF to LF
git-svn-id: svn://kolibrios.org@9367 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
49c44e14d4
commit
54c32b5c2d
@ -1,34 +1,34 @@
|
|||||||
#!/usr/bin/python3
|
#!/bin/python3
|
||||||
# Copyright Magomed Kostoev
|
# Copyright Magomed Kostoev
|
||||||
# Published under MIT license
|
# Published under MIT license
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
def log(s, end = "\n"):
|
def log(s, end = "\n"):
|
||||||
print(s, end = end, flush = True)
|
print(s, end = end, flush = True)
|
||||||
|
|
||||||
def install_python_script(src, dst, tools_lib):
|
def install_python_script(src, dst, tools_lib):
|
||||||
log(f"Copying {src}... ", end = "")
|
log(f"Copying {src}... ", end = "")
|
||||||
|
|
||||||
with open(src) as src_file:
|
with open(src) as src_file:
|
||||||
script = src_file.read()
|
script = src_file.read()
|
||||||
tools_lib_escaped = tools_lib.replace("\\", "\\\\")
|
tools_lib_escaped = tools_lib.replace("\\", "\\\\")
|
||||||
repl_from = "path_to_lib = '../lib'"
|
repl_from = "path_to_lib = '../lib'"
|
||||||
repl_to = f"path_to_lib ='{tools_lib_escaped}'"
|
repl_to = f"path_to_lib ='{tools_lib_escaped}'"
|
||||||
script = script.replace(repl_from, repl_to, 1)
|
script = script.replace(repl_from, repl_to, 1)
|
||||||
with open(dst, "w") as dst_file:
|
with open(dst, "w") as dst_file:
|
||||||
dst_file.write(script)
|
dst_file.write(script)
|
||||||
|
|
||||||
log(f"Done")
|
log(f"Done")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
tools_get_started_py = os.path.abspath(__file__)
|
tools_get_started_py = os.path.abspath(__file__)
|
||||||
tools = os.sep.join(tools_get_started_py.split(os.sep)[:-1])
|
tools = os.sep.join(tools_get_started_py.split(os.sep)[:-1])
|
||||||
tools_lib = os.sep.join([tools, "lib"])
|
tools_lib = os.sep.join([tools, "lib"])
|
||||||
tools_workspace = os.sep.join([tools, "workspace"])
|
tools_workspace = os.sep.join([tools, "workspace"])
|
||||||
# Copy scripts from _tools/workspace to current folder, but let them know
|
# Copy scripts from _tools/workspace to current folder, but let them know
|
||||||
# where the _tools/lib is (change their value of tools_lib variable)
|
# where the _tools/lib is (change their value of tools_lib variable)
|
||||||
tools_workspace_run_py = os.sep.join([tools_workspace, "run.py"])
|
tools_workspace_run_py = os.sep.join([tools_workspace, "run.py"])
|
||||||
tools_workspace_build_py = os.sep.join([tools_workspace, "build.py"])
|
tools_workspace_build_py = os.sep.join([tools_workspace, "build.py"])
|
||||||
install_python_script(tools_workspace_run_py, "run.py", tools_lib)
|
install_python_script(tools_workspace_run_py, "run.py", tools_lib)
|
||||||
install_python_script(tools_workspace_build_py, "build.py", tools_lib)
|
install_python_script(tools_workspace_build_py, "build.py", tools_lib)
|
||||||
|
@ -1,153 +1,153 @@
|
|||||||
# Copyright Magomed Kostoev
|
# Copyright Magomed Kostoev
|
||||||
# Published under MIT license
|
# Published under MIT license
|
||||||
|
|
||||||
class Rule:
|
class Rule:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_config(config_name):
|
def get_config(config_name):
|
||||||
if config_name == "KPACK_CMD":
|
if config_name == "KPACK_CMD":
|
||||||
# Just never pack the file for now
|
# Just never pack the file for now
|
||||||
return ""
|
return ""
|
||||||
else:
|
else:
|
||||||
print(f"Unknown config name: {config_name}")
|
print(f"Unknown config name: {config_name}")
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
def skip_whitespaces(src, ptr):
|
def skip_whitespaces(src, ptr):
|
||||||
while len(src) > ptr and src[ptr] == " ":
|
while len(src) > ptr and src[ptr] == " ":
|
||||||
ptr += 1
|
ptr += 1
|
||||||
return ptr
|
return ptr
|
||||||
|
|
||||||
# Returns True if @src has @string starting from @ptr index
|
# Returns True if @src has @string starting from @ptr index
|
||||||
def match_string(src, ptr, string):
|
def match_string(src, ptr, string):
|
||||||
if len(src) <= ptr + len(string):
|
if len(src) <= ptr + len(string):
|
||||||
return False
|
return False
|
||||||
for i in range(len(string)):
|
for i in range(len(string)):
|
||||||
if src[ptr + i] != string[i]:
|
if src[ptr + i] != string[i]:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def parse_tup_getconfig(src, ptr):
|
def parse_tup_getconfig(src, ptr):
|
||||||
# Skip get straight to the argument
|
# Skip get straight to the argument
|
||||||
ptr += len("tup.getconfig(")
|
ptr += len("tup.getconfig(")
|
||||||
ptr = skip_whitespaces(src, ptr)
|
ptr = skip_whitespaces(src, ptr)
|
||||||
if src[ptr] != "\"":
|
if src[ptr] != "\"":
|
||||||
print("Expected \"config name\" as tup.getconfig parameter")
|
print("Expected \"config name\" as tup.getconfig parameter")
|
||||||
exit()
|
exit()
|
||||||
(config_name, ptr) = parse_string(src, ptr)
|
(config_name, ptr) = parse_string(src, ptr)
|
||||||
ptr = skip_whitespaces(src, ptr)
|
ptr = skip_whitespaces(src, ptr)
|
||||||
# Skip closing parenthese of the tup.getconfig call
|
# Skip closing parenthese of the tup.getconfig call
|
||||||
assert(src[ptr] == ")")
|
assert(src[ptr] == ")")
|
||||||
ptr += 1
|
ptr += 1
|
||||||
return (get_config(config_name), ptr)
|
return (get_config(config_name), ptr)
|
||||||
|
|
||||||
def parse_string(src, ptr):
|
def parse_string(src, ptr):
|
||||||
ptr += 1
|
ptr += 1
|
||||||
string = ""
|
string = ""
|
||||||
while src[ptr] != "\"":
|
while src[ptr] != "\"":
|
||||||
string += src[ptr]
|
string += src[ptr]
|
||||||
ptr += 1
|
ptr += 1
|
||||||
# Skip the closing "\""
|
# Skip the closing "\""
|
||||||
ptr += 1
|
ptr += 1
|
||||||
ptr = skip_whitespaces(src, ptr)
|
ptr = skip_whitespaces(src, ptr)
|
||||||
# Check if we have concatination here
|
# Check if we have concatination here
|
||||||
if match_string(src, ptr, ".."):
|
if match_string(src, ptr, ".."):
|
||||||
# Skip the ".."
|
# Skip the ".."
|
||||||
ptr += 2
|
ptr += 2
|
||||||
# The expression parsing should result in a string
|
# The expression parsing should result in a string
|
||||||
(string_to_add, ptr) = parse_expression(src, ptr)
|
(string_to_add, ptr) = parse_expression(src, ptr)
|
||||||
# Concat our string to the resulting string
|
# Concat our string to the resulting string
|
||||||
string += string_to_add
|
string += string_to_add
|
||||||
return (string, ptr)
|
return (string, ptr)
|
||||||
|
|
||||||
def parse_expression(src, ptr):
|
def parse_expression(src, ptr):
|
||||||
ptr = skip_whitespaces(src, ptr)
|
ptr = skip_whitespaces(src, ptr)
|
||||||
result = "WAT?!"
|
result = "WAT?!"
|
||||||
if src[ptr] == "\"":
|
if src[ptr] == "\"":
|
||||||
(result, ptr) = parse_string(src, ptr)
|
(result, ptr) = parse_string(src, ptr)
|
||||||
elif match_string(src, ptr, "tup.getconfig("):
|
elif match_string(src, ptr, "tup.getconfig("):
|
||||||
(result, ptr) = parse_tup_getconfig(src, ptr)
|
(result, ptr) = parse_tup_getconfig(src, ptr)
|
||||||
else:
|
else:
|
||||||
print(f"Can't handle anything starting with '{src[ptr]}'")
|
print(f"Can't handle anything starting with '{src[ptr]}'")
|
||||||
exit(-1)
|
exit(-1)
|
||||||
ptr = skip_whitespaces(src, ptr)
|
ptr = skip_whitespaces(src, ptr)
|
||||||
return (result, ptr)
|
return (result, ptr)
|
||||||
|
|
||||||
def expect_comma(src, ptr):
|
def expect_comma(src, ptr):
|
||||||
comma_skept = False
|
comma_skept = False
|
||||||
ptr = skip_whitespaces(src, ptr)
|
ptr = skip_whitespaces(src, ptr)
|
||||||
if src[ptr] == ",":
|
if src[ptr] == ",":
|
||||||
ptr += 1
|
ptr += 1
|
||||||
return (True, ptr)
|
return (True, ptr)
|
||||||
else:
|
else:
|
||||||
return (False, ptr)
|
return (False, ptr)
|
||||||
|
|
||||||
def parse_arguments(src, ptr):
|
def parse_arguments(src, ptr):
|
||||||
result = []
|
result = []
|
||||||
# Parse first argument
|
# Parse first argument
|
||||||
(argument, ptr) = parse_expression(src, ptr)
|
(argument, ptr) = parse_expression(src, ptr)
|
||||||
result.append(argument)
|
result.append(argument)
|
||||||
(comma_encoutered, ptr) = expect_comma(src, ptr)
|
(comma_encoutered, ptr) = expect_comma(src, ptr)
|
||||||
# Parse the second argument if it's there
|
# Parse the second argument if it's there
|
||||||
if comma_encoutered:
|
if comma_encoutered:
|
||||||
(argument, ptr) = parse_expression(src, ptr)
|
(argument, ptr) = parse_expression(src, ptr)
|
||||||
result.append(argument)
|
result.append(argument)
|
||||||
(comma_encoutered, ptr) = expect_comma(src, ptr)
|
(comma_encoutered, ptr) = expect_comma(src, ptr)
|
||||||
# Parse third argument if it's there
|
# Parse third argument if it's there
|
||||||
if comma_encoutered:
|
if comma_encoutered:
|
||||||
(argument, ptr) = parse_expression(src, ptr)
|
(argument, ptr) = parse_expression(src, ptr)
|
||||||
result.append(argument)
|
result.append(argument)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def parse_rule(src, ptr):
|
def parse_rule(src, ptr):
|
||||||
# Get straight to the first argument
|
# Get straight to the first argument
|
||||||
ptr += len("tup.rule(")
|
ptr += len("tup.rule(")
|
||||||
# Parse the arguments
|
# Parse the arguments
|
||||||
args = parse_arguments(src, ptr)
|
args = parse_arguments(src, ptr)
|
||||||
# Build the rule object
|
# Build the rule object
|
||||||
result = Rule()
|
result = Rule()
|
||||||
if len(args) == 3:
|
if len(args) == 3:
|
||||||
result.input = args[0]
|
result.input = args[0]
|
||||||
result.command = args[1]
|
result.command = args[1]
|
||||||
result.output = args[2]
|
result.output = args[2]
|
||||||
# Replace %f with input file in rule's command
|
# Replace %f with input file in rule's command
|
||||||
if type(result.input == str):
|
if type(result.input == str):
|
||||||
result.command = result.command.replace("%f", result.input)
|
result.command = result.command.replace("%f", result.input)
|
||||||
else:
|
else:
|
||||||
print("Command building with non-string tup.rule's first argument"
|
print("Command building with non-string tup.rule's first argument"
|
||||||
+ " isn't implemented")
|
+ " isn't implemented")
|
||||||
exit()
|
exit()
|
||||||
# Replace %o with output file in rule's command
|
# Replace %o with output file in rule's command
|
||||||
if type(result.output == str):
|
if type(result.output == str):
|
||||||
result.command = result.command.replace("%o", result.output)
|
result.command = result.command.replace("%o", result.output)
|
||||||
else:
|
else:
|
||||||
print("Command building with non-string tup.rule's first argument"
|
print("Command building with non-string tup.rule's first argument"
|
||||||
+ " isn't implemented")
|
+ " isn't implemented")
|
||||||
exit()
|
exit()
|
||||||
elif len(args) == 2:
|
elif len(args) == 2:
|
||||||
result.input = []
|
result.input = []
|
||||||
result.command = args[0]
|
result.command = args[0]
|
||||||
result.output = args[1]
|
result.output = args[1]
|
||||||
else:
|
else:
|
||||||
print(f"tup.rule can only take 2 or 3 arguments, not {len(args)}")
|
print(f"tup.rule can only take 2 or 3 arguments, not {len(args)}")
|
||||||
exit(-1)
|
exit(-1)
|
||||||
# Unify the API - return arrays as input and output
|
# Unify the API - return arrays as input and output
|
||||||
if type(result.input) == str:
|
if type(result.input) == str:
|
||||||
result.input = [ result.input ]
|
result.input = [ result.input ]
|
||||||
else:
|
else:
|
||||||
assert(type(result.input) == list)
|
assert(type(result.input) == list)
|
||||||
if type(result.output) == str:
|
if type(result.output) == str:
|
||||||
result.output = [ result.output ]
|
result.output = [ result.output ]
|
||||||
else:
|
else:
|
||||||
assert(type(result.output) == list)
|
assert(type(result.output) == list)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def parse(file_name):
|
def parse(file_name):
|
||||||
rules = []
|
rules = []
|
||||||
with open(file_name) as f:
|
with open(file_name) as f:
|
||||||
tupfile = f.read()
|
tupfile = f.read()
|
||||||
rule_begin_index = tupfile.find("tup.rule(")
|
rule_begin_index = tupfile.find("tup.rule(")
|
||||||
while (rule_begin_index != -1):
|
while (rule_begin_index != -1):
|
||||||
rules.append(parse_rule(tupfile, rule_begin_index))
|
rules.append(parse_rule(tupfile, rule_begin_index))
|
||||||
# Find the next tup.rule call
|
# Find the next tup.rule call
|
||||||
rule_begin_index = tupfile.find("tup.rule(", rule_begin_index + len("tup.rule("))
|
rule_begin_index = tupfile.find("tup.rule(", rule_begin_index + len("tup.rule("))
|
||||||
return rules
|
return rules
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
path_to_lib = '../lib'
|
path_to_lib = '../lib'
|
||||||
sys.path.append(path_to_lib)
|
sys.path.append(path_to_lib)
|
||||||
|
|
||||||
import tupfile_parser
|
import tupfile_parser
|
||||||
|
|
||||||
def build():
|
def build():
|
||||||
if not os.path.exists("Tupfile.lua"):
|
if not os.path.exists("Tupfile.lua"):
|
||||||
print("No Tupfile.lua, can't build anything")
|
print("No Tupfile.lua, can't build anything")
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
tup_rules = tupfile_parser.parse("Tupfile.lua")
|
tup_rules = tupfile_parser.parse("Tupfile.lua")
|
||||||
program_files = []
|
program_files = []
|
||||||
for rule in tup_rules:
|
for rule in tup_rules:
|
||||||
# TODO: Manage source dependencies
|
# TODO: Manage source dependencies
|
||||||
# TODO: Inform about tools required for the build
|
# TODO: Inform about tools required for the build
|
||||||
os.system(rule.command)
|
os.system(rule.command)
|
||||||
program_files += rule.output
|
program_files += rule.output
|
||||||
return program_files
|
return program_files
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
build()
|
build()
|
@ -1,103 +1,103 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import shutil
|
import shutil
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
import build
|
import build
|
||||||
|
|
||||||
path_to_lib = '../lib'
|
path_to_lib = '../lib'
|
||||||
sys.path.append(path_to_lib)
|
sys.path.append(path_to_lib)
|
||||||
|
|
||||||
from makeflop import Floppy
|
from makeflop import Floppy
|
||||||
|
|
||||||
# TODO: Move into _tools/lib
|
# TODO: Move into _tools/lib
|
||||||
def get_file_directory(path):
|
def get_file_directory(path):
|
||||||
path = path.replace("\\", "/")
|
path = path.replace("\\", "/")
|
||||||
if "/" in path:
|
if "/" in path:
|
||||||
folder = "/".join(path.split("/")[:-1])
|
folder = "/".join(path.split("/")[:-1])
|
||||||
if folder == "":
|
if folder == "":
|
||||||
return "/" # It was a file in the root folder
|
return "/" # It was a file in the root folder
|
||||||
return folder
|
return folder
|
||||||
else:
|
else:
|
||||||
return "." # Just a filename, let's return current folder
|
return "." # Just a filename, let's return current folder
|
||||||
|
|
||||||
# TODO: Move into _tools/lib
|
# TODO: Move into _tools/lib
|
||||||
def is_win32():
|
def is_win32():
|
||||||
return True if sys.platform == "win32" else False
|
return True if sys.platform == "win32" else False
|
||||||
|
|
||||||
# TODO: Move into _tools/lib
|
# TODO: Move into _tools/lib
|
||||||
def is_linux():
|
def is_linux():
|
||||||
return True if sys.platform == "linux" or sys.platform == "linux2" else False
|
return True if sys.platform == "linux" or sys.platform == "linux2" else False
|
||||||
|
|
||||||
# TODO: Move into _tools/lib
|
# TODO: Move into _tools/lib
|
||||||
def is_osx():
|
def is_osx():
|
||||||
return True if sys.platform == "darwin" else False
|
return True if sys.platform == "darwin" else False
|
||||||
|
|
||||||
# TODO: Move into _tools/lib
|
# TODO: Move into _tools/lib
|
||||||
def log(s, end = "\n"):
|
def log(s, end = "\n"):
|
||||||
print(s, end = end, flush = True)
|
print(s, end = end, flush = True)
|
||||||
|
|
||||||
# TODO: Move into _tools/lib
|
# TODO: Move into _tools/lib
|
||||||
def download(link, path):
|
def download(link, path):
|
||||||
log(f"Downloading {path}... ", end = "")
|
log(f"Downloading {path}... ", end = "")
|
||||||
urllib.request.urlretrieve(link, path)
|
urllib.request.urlretrieve(link, path)
|
||||||
log("Done.")
|
log("Done.")
|
||||||
|
|
||||||
# TODO: Move into _tools/lib
|
# TODO: Move into _tools/lib
|
||||||
def path(*args):
|
def path(*args):
|
||||||
return os.sep.join(args)
|
return os.sep.join(args)
|
||||||
|
|
||||||
# TODO: Move into _tools/lib
|
# TODO: Move into _tools/lib
|
||||||
def run_qemu(start_dir = "workspace"):
|
def run_qemu(start_dir = "workspace"):
|
||||||
qemu_command = f"qemu-system-i386"
|
qemu_command = f"qemu-system-i386"
|
||||||
flags = ""
|
flags = ""
|
||||||
flags += "-L . " # IDK why it does not work without this
|
flags += "-L . " # IDK why it does not work without this
|
||||||
flags += "-m 128 "
|
flags += "-m 128 "
|
||||||
flags += f"-drive format=raw,file={start_dir}/kolibri.img,index=0,if=floppy -boot a "
|
flags += f"-drive format=raw,file={start_dir}/kolibri.img,index=0,if=floppy -boot a "
|
||||||
flags += "-vga vmware "
|
flags += "-vga vmware "
|
||||||
flags += "-net nic,model=rtl8139 -net user "
|
flags += "-net nic,model=rtl8139 -net user "
|
||||||
flags += "-soundhw ac97 "
|
flags += "-soundhw ac97 "
|
||||||
if is_win32():
|
if is_win32():
|
||||||
qemu_full_path = shutil.which(qemu_command)
|
qemu_full_path = shutil.which(qemu_command)
|
||||||
qemu_directory = get_file_directory(qemu_full_path)
|
qemu_directory = get_file_directory(qemu_full_path)
|
||||||
flags += f"-L {qemu_directory} "
|
flags += f"-L {qemu_directory} "
|
||||||
s = f"{qemu_command} {flags}"
|
s = f"{qemu_command} {flags}"
|
||||||
qemu_stdout = open(f"{start_dir}/qemu_stdout.log", "w")
|
qemu_stdout = open(f"{start_dir}/qemu_stdout.log", "w")
|
||||||
qemu_stderr = open(f"{start_dir}/qemu_stderr.log", "w")
|
qemu_stderr = open(f"{start_dir}/qemu_stderr.log", "w")
|
||||||
if is_win32():
|
if is_win32():
|
||||||
return subprocess.Popen(s, bufsize = 0, stdout = qemu_stdout, stderr = qemu_stderr, stdin = subprocess.DEVNULL, shell = True, start_new_session = True)
|
return subprocess.Popen(s, bufsize = 0, stdout = qemu_stdout, stderr = qemu_stderr, stdin = subprocess.DEVNULL, shell = True, start_new_session = True)
|
||||||
else:
|
else:
|
||||||
a = shlex.split(s)
|
a = shlex.split(s)
|
||||||
return subprocess.Popen(a, bufsize = 0, stdout = qemu_stdout, stderr = qemu_stderr, stdin = subprocess.DEVNULL, start_new_session = True)
|
return subprocess.Popen(a, bufsize = 0, stdout = qemu_stdout, stderr = qemu_stderr, stdin = subprocess.DEVNULL, start_new_session = True)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
program_files = build.build()
|
program_files = build.build()
|
||||||
|
|
||||||
os.makedirs("workspace", exist_ok = True)
|
os.makedirs("workspace", exist_ok = True)
|
||||||
|
|
||||||
if not os.path.exists("workspace/kolibri.img"):
|
if not os.path.exists("workspace/kolibri.img"):
|
||||||
img_url = "http://builds.kolibrios.org/eng/data/data/kolibri.img"
|
img_url = "http://builds.kolibrios.org/eng/data/data/kolibri.img"
|
||||||
download(img_url, "workspace/kolibri.img")
|
download(img_url, "workspace/kolibri.img")
|
||||||
|
|
||||||
# Open the IMG
|
# Open the IMG
|
||||||
with open("workspace/kolibri.img", "rb") as img:
|
with open("workspace/kolibri.img", "rb") as img:
|
||||||
img_data = img.read()
|
img_data = img.read()
|
||||||
img = Floppy(img_data)
|
img = Floppy(img_data)
|
||||||
|
|
||||||
# Remove unuseful folders
|
# Remove unuseful folders
|
||||||
img.delete_path("GAMES")
|
img.delete_path("GAMES")
|
||||||
img.delete_path("DEMOS")
|
img.delete_path("DEMOS")
|
||||||
img.delete_path("3D")
|
img.delete_path("3D")
|
||||||
|
|
||||||
log("Moving program files into kolibri image... ", end = "")
|
log("Moving program files into kolibri image... ", end = "")
|
||||||
for file_name in program_files:
|
for file_name in program_files:
|
||||||
with open(file_name, "rb") as file:
|
with open(file_name, "rb") as file:
|
||||||
file_data = file.read()
|
file_data = file.read()
|
||||||
if not img.add_file_path(file_name, file_data):
|
if not img.add_file_path(file_name, file_data):
|
||||||
print(f"Coudn't move {file_name} into IMG")
|
print(f"Coudn't move {file_name} into IMG")
|
||||||
img.save("workspace/kolibri.img")
|
img.save("workspace/kolibri.img")
|
||||||
log("Done")
|
log("Done")
|
||||||
|
|
||||||
# TODO: Autorun
|
# TODO: Autorun
|
||||||
run_qemu()
|
run_qemu()
|
||||||
|
Loading…
Reference in New Issue
Block a user