我是Stackoverflow的新手,这是我的第一个问题。我已经从各种问题中搜索了是否有可能基于我的专业化Web语言php创建本机桌面应用程序。
我发现一些话题谈论一个名为nightrain的github存储库。我决定下载它进行尝试,并且还将php脚本版本更新为7.2.10,但是每次我尝试启动build.py
脚本时,我的mac consolle上都会打印错误。我不是python专家,所以我想问问是否有人可以帮助我解决这个问题,我在Google上进行了一些搜索,但是没有有关此脚本的文档。
这是报告的错误
yur $ python /用户/ yur /桌面/nightrain-master/build.py 追溯(最近一次通话): 在第19行中输入“ /Users/yur/Desktop/nightrain-master/build.py”文件 编译器.compile_nightrain_mac() 在compile_nightrain_mac中,文件“ /Users/yur/Desktop/nightrain-master/Classes/Compiler.py”,行179 调用([[“ pyinstaller.py”,“ --clean”,“ -w”,“ -y”,“ -F”,spec_path,application_icon,“ -n”,“ nightrain”,“ Application.py”]) 调用中的文件“ /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py”,第522行 返回Popen(* popenargs,** kwargs).wait() init 中的文件“ /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py”,第710行 errread,errwrite) _execute_child中的文件“ /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py”,行1335 提高child_exception OSError:[Errno 2]没有这样的文件或目录
这是build.py脚本的代码
from Classes.Compiler import Compiler
from Classes.Settings import Settings
settings = Settings()
compiler = Compiler("./dist", "./nrtmp", "./Resources")
# clean output folder
compiler.clean_dist()
# compile nightrain
if compiler.is_windows():
compiler.compile_nightrain_windows()
if compiler.is_linux():
compiler.compile_nightrain_linux()
if compiler.is_mac():
compiler.compile_nightrain_mac()
# compile PHP
if compiler.is_windows():
compiler.compile_php_windows()
if compiler.is_linux():
compiler.compile_php_linux()
if compiler.is_mac():
compiler.compile_php_mac()
# copy required files
if compiler.is_windows():
compiler.copy_resources()
compiler.copy_php_windows()
settings.create_default_settings(compiler.get_settings_ini_dest())
if compiler.is_linux():
compiler.copy_resources()
compiler.copy_php_linux()
compiler.copy_php_ini_linux()
settings.create_default_settings(compiler.get_settings_ini_dest())
if compiler.is_mac():
app_version_dir = "%s/%s" % (compiler.output_dir, "app_version")
shell_version_dir = "%s/%s" % (compiler.output_dir, "shell_version")
nightrain_app_file_dest = "%s/nightrain.app" % app_version_dir
nightrain_shell_file_dest = "%s/nightrain" % shell_version_dir
nightrain_app_file_source = "%s/nightrain.app" % compiler.output_dir
nightrain_shell_file_source = "%s/nightrain" % compiler.output_dir
# create the output directories
compiler.make_dir(app_version_dir)
compiler.make_dir(shell_version_dir)
# move nightrain.app to app version dir
compiler.move_file(nightrain_app_file_source, nightrain_app_file_dest)
# move nightrain shell version to shell version dir
compiler.move_file(nightrain_shell_file_source, nightrain_shell_file_dest)
# copy PHP libraries to app version
destination = "%s/Contents/MacOS/lib/php" % nightrain_app_file_dest
compiler.copy_php_mac(destination)
# copy PHP libraries to shell version
destination = "%s/lib/php" % shell_version_dir
compiler.copy_php_mac(destination)
# copy resources to app version
mac_os_x_dir = "%s/Contents/MacOS" % nightrain_app_file_dest
compiler.copy_resources(mac_os_x_dir)
settings.create_default_settings("%s/%s" % (mac_os_x_dir, "settings.ini"))
# copy resources to shell version
compiler.copy_resources(shell_version_dir)
settings.create_default_settings("%s/%s" % (shell_version_dir, "settings.ini"))
# copy PHP ini to app version
destination = "%s/Contents/MacOS/lib/php/bin/php.ini" % nightrain_app_file_dest
compiler.copy_php_ini_mac(destination)
# copy php ini to app version
destination = "%s/lib/php/bin/php.ini" % shell_version_dir
compiler.copy_php_ini_mac(destination)
这是Compiler.py脚本代码
import sys
import os
import shutil
import urllib
import zipfile
import Settings
from subprocess import call
class Compiler:
build_dir = "./build"
output_dir = "./dist"
tmp_dir = "./nrtmp"
resources_dir = "./resources"
php_linux_binary_dir = "/home/naetech/php"
php_mac_binary_dir = "/Users/naetech/php"
php_windows_binary_dir = "C:\\nightrain_php"
def __init__(self, output_dir, tmp_dir, resources_dir):
self.output_dir = output_dir
self.tmp_dir = tmp_dir
self.resources_dir = resources_dir
@staticmethod
def is_linux():
platform = sys.platform
if "linux" in platform:
return True
else:
return False
@staticmethod
def is_windows():
if "win" in sys.platform and "darwin" not in sys.platform:
return True
else:
return False
@staticmethod
def is_mac():
if "darwin" in sys.platform:
return True
else:
return False
def compile_php_windows(self):
# remove the old binary
if os.path.exists(self.php_windows_binary_dir):
shutil.rmtree(self.php_windows_binary_dir)
# create a random tmp directory
if os.path.exists(self.tmp_dir):
shutil.rmtree(self.tmp_dir)
os.mkdir(self.tmp_dir)
# Non thread safe 64bit vers https://windows.php.net/downloads/releases/php-7.2.10-nts-Win32-VC15-x64.zip
# Thread safe 32bit vers https://windows.php.net/downloads/releases/php-7.2.10-Win32-VC15-x86.zip
# download the latest version of PHP
php_file_zip_download_link = "https://windows.php.net/downloads/releases/php-7.2.10-Win32-VC15-x86.zip"
php_file_zip_dest = "%s/%s" % (self.tmp_dir, "php-7.2.10-Win32-VC15-x86.zip")
print "Downloading %s" % php_file_zip_download_link
urllib.urlretrieve(php_file_zip_download_link, php_file_zip_dest)
print "Finished downloading %s" % php_file_zip_download_link
zfile = zipfile.ZipFile(php_file_zip_dest)
for name in zfile.namelist():
(dirname, filename) = os.path.split(name)
extracted_dir = "%s\\%s" % (self.php_windows_binary_dir, dirname)
print "Decompressing " + filename + " on " + dirname
if not os.path.exists(extracted_dir):
os.makedirs(extracted_dir)
zfile.extract(name, extracted_dir)
return True
def compile_php_mac(self):
# remove the old binary
if os.path.exists(self.php_mac_binary_dir):
shutil.rmtree(self.php_mac_binary_dir)
# create a random tmp directory
if os.path.exists(self.tmp_dir):
shutil.rmtree(self.tmp_dir)
os.mkdir(self.tmp_dir)
# download the latest version of PHP
php_tar_file_save_location = "%s/%s" % (self.tmp_dir, "php7210.tar.gz")
# fixme add a config file so the developers can update this link without modifying the source codes
# http://us1.php.net/get/php-7.2.10.tar.gz/from/this/mirror
php_tar_download_link = "http://us1.php.net/get/php-7.2.10.tar.gz/from/this/mirror"
self.download_file(php_tar_download_link, php_tar_file_save_location)
php_extracted_dir = "%s/%s" % (self.tmp_dir, "php7210")
os.mkdir(php_extracted_dir)
call(["tar", "-C", php_extracted_dir, "-zxvf", php_tar_file_save_location])
# compile PHP
php_source_dir = "%s/%s" % (php_extracted_dir, "php-7.2.10")
configure_command = "cd %s && ./configure --prefix=%s " \
"--enable-bcmath " \
"--enable-calendar " \
"--enable-mbstring " \
"--with-curl " \
"--with-gd " \
"--with-mysql " \
"--with-pdo-mysql " \
"--with-sqlite3" \
% (php_source_dir, self.php_mac_binary_dir)
call(configure_command, shell=True)
make_command = "cd %s && make && make install" % php_source_dir
call(make_command, shell=True)
return True
def compile_php_linux(self):
# remove the old binary
if os.path.exists(self.php_linux_binary_dir):
shutil.rmtree(self.php_linux_binary_dir)
# create a random tmp directory
if os.path.exists(self.tmp_dir):
shutil.rmtree(self.tmp_dir)
os.mkdir(self.tmp_dir)
# download the latest version of PHP
phpTarFile = "%s/%s" % (self.tmp_dir, "php7210.tar.gz")
call(["wget", "http://us1.php.net/get/php-7.2.10.tar.gz/from/this/mirror", "-O", phpTarFile])
phpDir = "%s/%s" % (self.tmp_dir, "php7210")
os.mkdir(phpDir)
call(["tar", "-C", phpDir, "-zxvf", phpTarFile])
# compile PHP
phpSourceDir = "%s/%s" % (phpDir, "php-7.2.10")
configureCommand = "cd %s && ./configure --prefix=%s " \
"--enable-bcmath " \
"--enable-calendar " \
"--enable-mbstring " \
"--with-curl " \
"--with-gd " \
"--with-mysql " \
"--with-pdo-mysql " \
"--with-sqlite3" \
% (phpSourceDir, self.php_linux_binary_dir)
call(configureCommand, shell=True)
makeCommand = "cd %s && make && make install" % (phpSourceDir)
call(makeCommand, shell=True)
return True
def compile_nightrain_windows(self):
self.clean_unncessary_files()
spec_path = "--specpath=%s/%s" % (self.build_dir, "specs")
application_icon = "--icon=%s/%s" % (self.resources_dir, "icon.ico")
# fixme When using the -w option, the final executable causes error
call(["pyinstaller.py", "--clean", "-y", "-F", spec_path, application_icon, "-n", "nightrain", "Application.py"],
shell=True)
self.clean_unncessary_files()
def compile_nightrain_linux(self):
self.clean_unncessary_files()
spec_path = "--specpath=%s/%s" % (self.build_dir, "specs")
call(["pyinstaller", "--clean", "-y", "-F", spec_path, "-n", "nightrain", "Application.py"])
self.clean_unncessary_files()
def compile_nightrain_mac(self):
self.clean_unncessary_files()
spec_path = "--specpath=%s/%s" % (self.build_dir, "specs")
application_icon = "--icon=%s/%s" % (self.resources_dir, "icon.ico")
call(["pyinstaller.py", "--clean", "-w", "-y", "-F", spec_path, application_icon, "-n", "nightrain", "Application.py"])
self.clean_unncessary_files()
def make_dir(self, path):
if not os.path.exists(path):
try:
os.mkdir(path)
print "Successfully created: %s" % path
return True
except:
print "Could not create %s" % path
return False
else:
return False
def move_file(self, source, destination):
if os.path.exists(source):
try:
shutil.move(source, destination)
print "Successfully moved %s to %s" % (source, destination)
return True
except:
print "Could not move %s to %s" % (source, destination)
return False
else:
return False
def copy_file(self, source, destination):
success_msg = "Successfully copied %s to %s" % (source, destination)
failure_msg = "Could not copy %s to %s" % (source, destination)
if os.path.exists(source) and os.path.isdir(source):
try:
shutil.copytree(source, destination)
print success_msg
return True
except:
print failure_msg
return False
elif os.path.exists(source) and os.path.isfile(source):
try:
shutil.copyfile(source, destination)
print success_msg
return True
except:
print failure_msg
return False
else:
return False
def copy_resources(self, custom_output_dir=None):
items = [
"www",
"icon.png",
"LICENSE"
]
for item in items:
if item == "icon.png" and (self.is_windows() or self.is_mac()):
continue
source = "%s/%s" % (self.resources_dir, item)
if not custom_output_dir:
destination = "%s/%s" % (self.output_dir, item)
else:
destination = "%s/%s" % (custom_output_dir, item)
if os.path.exists(source):
error = "Could not copy item %s" % (item)
success = "Successfully copied %s to %s" % (source, destination)
if os.path.isfile(source):
try:
shutil.copyfile(source, destination)
print success
except:
print error
return False
else:
try:
shutil.copytree(source, destination)
print success
except:
print error
return False
else:
print "%s does not exist" % (item)
return False
def copy_php_windows(self):
destination = "%s/%s/%s" % (self.output_dir, "lib", "php")
if os.path.exists(self.php_windows_binary_dir):
try:
shutil.copytree(self.php_windows_binary_dir, destination)
print "Successfully copied %s to %s" % (self.php_windows_binary_dir, destination)
return True
except:
print "Could not copy %s to %s" % (self.php_windows_binary_dir, destination)
return False
else:
return False
def copy_php_mac(self, destination_dir):
if not self.copy_file(self.php_mac_binary_dir, destination_dir):
return False
return True
def copy_php_linux(self):
destination = "%s/%s/%s" % (self.output_dir, "lib", "php")
if os.path.exists(self.php_linux_binary_dir):
try:
shutil.copytree(self.php_linux_binary_dir, destination)
print "Successfully copied %s to %s" % (self.php_linux_binary_dir, destination)
return True
except:
print "Could not copy %s to %s" % (self.php_linux_binary_dir, destination)
return False
else:
return False
def copy_php_ini_linux(self):
src = "%s/%s" % (self.resources_dir, "php.ini")
destination = self.get_php_ini_dest()
try:
shutil.copyfile(src, destination)
print "Successfully copied %s to %s" % (src, destination)
return True
except:
return False
def copy_php_ini_windows(self):
php_ini_src = "%s\\%s" % (self.php_windows_binary_dir, "php.ini-production")
php_ini_dest = self.get_php_ini_dest()
if os.path.exists(php_ini_src):
try:
shutil.copyfile(php_ini_src, php_ini_dest)
print "Successfully copied %s to %s" % (php_ini_src, php_ini_dest)
# replace configs
php_ini_configs = [
'; extension_dir = "ext"',
';extension=php_gd2.dll',
';extension=php_mbstring.dll',
';extension=php_sqlite3.dll'
]
for config in php_ini_configs:
config_uncommented = config.replace(";", "").strip()
Settings.Settings.replace(php_ini_dest, config, config_uncommented)
print "Replaced %s with %s in %s" % (config, config_uncommented, php_ini_dest)
return True
except:
return False
else:
print "Could not find %s" % php_ini_src
def copy_php_ini_mac(self, dest):
source = "%s/settings.ini" % self.resources_dir
return self.copy_file(source, dest)
def clean_dist(self):
if os.path.exists(self.output_dir):
shutil.rmtree(self.output_dir)
def clean_unncessary_files(self):
if os.path.exists(self.tmp_dir):
shutil.rmtree(self.tmp_dir)
if os.path.exists(self.build_dir):
shutil.rmtree(self.build_dir)
def remove_file(self, file_path):
if os.path.exists(file_path):
shutil.rmtree(file_path)
def get_php_ini_dest(self):
if self.is_linux() or self.is_mac():
return "%s/%s/%s/%s/%s" % (self.output_dir, "lib", "php", "bin", "php.ini")
elif self.is_windows():
return "%s/%s/%s/%s" % (self.output_dir, "lib", "php", "php.ini")
else:
return False
def get_settings_ini_dest(self):
return "%s/%s" % (self.output_dir, "settings.ini")
def download_file(self, download_link, where_to_save_file_including_file_name):
print "Downloading %s" % download_link
urllib.urlretrieve(download_link, where_to_save_file_including_file_name)
print "Finished downloading %s" % download_link
print "File saved to %s" % download_link