1 Star 0 Fork 0

zhuixixi / ycmd

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
update_clang.py 18.83 KB
一键复制 编辑 原始数据 按行查看 历史
Boris Staletic 提交于 2019-12-24 11:09 . Drop python2 support
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
#!/usr/bin/env python3
import argparse
import contextlib
import gzip
import os
import os.path as p
import platform
import shutil
import subprocess
import sys
import tempfile
import tarfile
import hashlib
from distutils.spawn import find_executable
try:
import lzma
except ImportError:
from backports import lzma
DIR_OF_THIS_SCRIPT = p.dirname( p.abspath( __file__ ) )
DIR_OF_THIRD_PARTY = p.join( DIR_OF_THIS_SCRIPT, 'third_party' )
sys.path[ 0:0 ] = [ p.join( DIR_OF_THIRD_PARTY, 'requests_deps', 'requests' ),
p.join( DIR_OF_THIRD_PARTY,
'requests_deps',
'urllib3',
'src' ),
p.join( DIR_OF_THIRD_PARTY, 'requests_deps', 'chardet' ),
p.join( DIR_OF_THIRD_PARTY, 'requests_deps', 'certifi' ),
p.join( DIR_OF_THIRD_PARTY, 'requests_deps', 'idna' ) ]
import requests
from io import BytesIO
def OnWindows():
return platform.system() == 'Windows'
def OnMac():
return platform.system() == 'Darwin'
LLVM_DOWNLOAD_DATA = {
'win32': {
'url': 'https://releases.llvm.org/{llvm_version}/{llvm_package}',
'format': 'nsis',
'llvm_package': 'LLVM-{llvm_version}-{os_name}.exe',
'clangd_package': {
'name': 'clangd-{llvm_version}-{os_name}.tar.bz2',
'files_to_copy': [
os.path.join( 'bin', 'clangd.exe' ),
]
},
'libclang_package': {
'name': 'libclang-{llvm_version}-{os_name}.tar.bz2',
'files_to_copy': [
os.path.join( 'bin', 'libclang.dll' ),
os.path.join( 'lib', 'libclang.lib' ),
]
}
},
'win64': {
'url': 'https://releases.llvm.org/{llvm_version}/{llvm_package}',
'format': 'nsis',
'llvm_package': 'LLVM-{llvm_version}-{os_name}.exe',
'clangd_package': {
'name': 'clangd-{llvm_version}-{os_name}.tar.bz2',
'files_to_copy': [
os.path.join( 'bin', 'clangd.exe' ),
]
},
'libclang_package': {
'name': 'libclang-{llvm_version}-{os_name}.tar.bz2',
'files_to_copy': [
os.path.join( 'bin', 'libclang.dll' ),
os.path.join( 'lib', 'libclang.lib' ),
]
}
},
'x86_64-apple-darwin': {
'url': 'https://homebrew.bintray.com/bottles/{llvm_package}',
'format': 'gzip',
'llvm_package': 'llvm-{llvm_version}.sierra.bottle.tar.gz',
'clangd_package': {
'name': 'clangd-{llvm_version}-{os_name}.tar.bz2',
'files_to_copy': [
os.path.join( 'bin', 'clangd' ),
]
},
'libclang_package': {
'name': 'libclang-{llvm_version}-{os_name}.tar.bz2',
'files_to_copy': [
{
'from': os.path.join( '{llvm_version}', 'lib', 'libclang.dylib' ),
'to': os.path.join( 'lib', 'libclang.dylib' ),
}
],
'run_after_extract':
lambda temporary_dir, llvm_version : _SetMacOSLibraryID(
os.path.join( temporary_dir,
llvm_version,
'lib',
'libclang.dylib' ),
'@rpath/libclang.dylib' )
}
},
'x86_64-unknown-linux-gnu': {
'url': ( 'https://github.com/ycm-core/llvm/'
'releases/download/{llvm_version}/{llvm_package}' ),
'format': 'lzma',
'llvm_package': 'clang+llvm-{llvm_version}-{os_name}.tar.xz',
'clangd_package': {
'name': 'clangd-{llvm_version}-{os_name}.tar.bz2',
'files_to_copy': [
os.path.join( 'bin', 'clangd' ),
]
},
'libclang_package': {
'name': 'libclang-{llvm_version}-{os_name}.tar.bz2',
'files_to_copy': [
os.path.join( 'lib', 'libclang.so' ),
os.path.join( 'lib', 'libclang.so.{llvm_version:.1}' )
]
}
},
'i386-unknown-freebsd11': {
'url': 'https://releases.llvm.org/{llvm_version}/{llvm_package}',
'format': 'lzma',
'llvm_package': 'clang+llvm-{llvm_version}-{os_name}.tar.xz',
'clangd_package': {
'name': 'clangd-{llvm_version}-{os_name}.tar.bz2',
'files_to_copy': [
os.path.join( 'bin', 'clangd' ),
]
},
'libclang_package': {
'name': 'libclang-{llvm_version}-{os_name}.tar.bz2',
'files_to_copy': [
os.path.join( 'lib', 'libclang.so' ),
os.path.join( 'lib', 'libclang.so.{llvm_version:.1}' )
]
}
},
'amd64-unknown-freebsd11': {
'url': 'https://releases.llvm.org/{llvm_version}/{llvm_package}',
'format': 'lzma',
'llvm_package': 'clang+llvm-{llvm_version}-{os_name}.tar.xz',
'clangd_package': {
'name': 'clangd-{llvm_version}-{os_name}.tar.bz2',
'files_to_copy': [
os.path.join( 'bin', 'clangd' ),
]
},
'libclang_package': {
'name': 'libclang-{llvm_version}-{os_name}.tar.bz2',
'files_to_copy': [
os.path.join( 'lib', 'libclang.so' ),
os.path.join( 'lib', 'libclang.so.{llvm_version:.1}' )
]
}
},
'aarch64-linux-gnu': {
'url': 'https://releases.llvm.org/{llvm_version}/{llvm_package}',
'format': 'lzma',
'llvm_package': 'clang+llvm-{llvm_version}-{os_name}.tar.xz',
'clangd_package': {
'name': 'clangd-{llvm_version}-{os_name}.tar.bz2',
'files_to_copy': [
os.path.join( 'bin', 'clangd' ),
]
},
'libclang_package': {
'name': 'libclang-{llvm_version}-{os_name}.tar.bz2',
'files_to_copy': [
os.path.join( 'lib', 'libclang.so' ),
os.path.join( 'lib', 'libclang.so.{llvm_version:.1}' )
]
}
},
'armv7a-linux-gnueabihf': {
'url': 'https://releases.llvm.org/{llvm_version}/{llvm_package}',
'format': 'lzma',
'llvm_package': 'clang+llvm-{llvm_version}-{os_name}.tar.xz',
'clangd_package': {
'name': 'clangd-{llvm_version}-{os_name}.tar.bz2',
'files_to_copy': [
os.path.join( 'bin', 'clangd' ),
]
},
'libclang_package': {
'name': 'libclang-{llvm_version}-{os_name}.tar.bz2',
'files_to_copy': [
os.path.join( 'lib', 'libclang.so' ),
os.path.join( 'lib', 'libclang.so.{llvm_version:.1}' )
]
}
},
}
def _SetMacOSLibraryID( lib_path, new_id ):
current_mode = os.stat( lib_path ).st_mode
try:
import stat
os.chmod( lib_path, current_mode | stat.S_IWUSR )
subprocess.check_call( [ 'install_name_tool', '-id', new_id, lib_path ] )
finally:
os.chmod( lib_path, current_mode )
@contextlib.contextmanager
def TemporaryDirectory( keep_temp ):
temp_dir = tempfile.mkdtemp()
try:
yield temp_dir
finally:
if keep_temp:
print( "*** Please delete temp dir: {}".format( temp_dir ) )
else:
shutil.rmtree( temp_dir )
def DownloadClangLicense( version, destination ):
print( 'Downloading license...' )
request = requests.get(
'https://releases.llvm.org/{version}/LICENSE.TXT'.format( version=version ),
stream = True )
request.raise_for_status()
file_name = os.path.join( destination, 'LICENSE.TXT' )
with open( file_name, 'wb' ) as f:
f.write( request.content )
request.close()
return file_name
def Download( url ):
print( 'Downloading {}'.format( url.rsplit( '/', 1 )[ -1 ] ) )
request = requests.get( url, stream=True )
request.raise_for_status()
content = request.content
request.close()
return content
def ExtractTar( uncompressed_data, destination ):
with tarfile.TarFile( fileobj=uncompressed_data, mode='r' ) as tar_file:
a_member = tar_file.getmembers()[ 0 ]
tar_file.extractall( destination )
# Determine the directory name
return os.path.join( destination, a_member.name.split( '/' )[ 0 ] )
def ExtractLZMA( compressed_data, destination ):
uncompressed_data = BytesIO( lzma.decompress( compressed_data ) )
return ExtractTar( uncompressed_data, destination )
def ExtractGZIP( compressed_data, destination ):
uncompressed_data = BytesIO( gzip.decompress( compressed_data ) )
return ExtractTar( uncompressed_data, destination )
def Extract7Z( llvm_package, archive, destination ):
# Extract with appropriate tool
if OnWindows():
import winreg
with winreg.OpenKey( winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\7-Zip' ) as key:
executable = os.path.join( winreg.QueryValueEx( key, "Path" )[ 0 ],
'7z.exe' )
elif OnMac():
# p7zip is available from homebrew (brew install p7zip)
executable = find_executable( '7z' )
else:
# On Linux, p7zip 16.02 is required.
executable = find_executable( '7z' )
command = [
executable,
'-y',
'x',
archive,
'-o' + destination
]
# Silence 7-Zip output.
subprocess.check_call( command, stdout = subprocess.PIPE )
return destination
def MakeBundle( files_to_copy,
license_file_name,
source_dir,
bundle_file_name,
hashes,
version ):
archive_name = os.path.basename( bundle_file_name )
print( 'Bundling files to {}'.format( archive_name ) )
with tarfile.open( name=bundle_file_name, mode='w:bz2' ) as tar_file:
tar_file.add( license_file_name, arcname='LICENSE.TXT' )
for item in files_to_copy:
if isinstance( item, dict ):
source_file_name = item[ 'from' ].format( llvm_version = version )
target_file_name = item[ 'to' ].format( llvm_version = version )
else:
source_file_name = item.format( llvm_version = version )
target_file_name = source_file_name
name = os.path.join( source_dir, source_file_name )
if not os.path.exists( name ):
raise RuntimeError( 'File {} does not exist.'.format( name ) )
tar_file.add( name = name, arcname = target_file_name )
sys.stdout.write( 'Calculating checksum: ' )
with open( bundle_file_name, 'rb' ) as f:
hashes[ archive_name ] = hashlib.sha256( f.read() ).hexdigest()
print( hashes[ archive_name ] )
def UploadBundleToBintray( user_name,
api_token,
subject,
os_name,
version,
bundle_file_name ):
print( 'Uploading to bintray...' )
repo = bundle_file_name[ : bundle_file_name.find( '-' ) ]
with open( bundle_file_name, 'rb' ) as bundle:
request = requests.put(
'https://api.bintray.com/content/{subject}/{repo}/{file_path}'.format(
subject = subject,
repo = repo,
file_path = os.path.basename( bundle_file_name ) ),
data = bundle,
auth = ( user_name, api_token ),
headers = {
'X-Bintray-Package': repo,
'X-Bintray-Version': version,
'X-Bintray-Publish': '1',
'X-Bintray-Override': '1',
} )
request.raise_for_status()
def ParseArguments():
parser = argparse.ArgumentParser()
parser.add_argument( 'version', action='store',
help = 'The LLVM version' )
parser.add_argument( '--bt-user', action='store',
help = 'Bintray user name. Defaults to environment '
'variable: YCMD_BINTRAY_USERNAME' )
parser.add_argument( '--bt-subject', action='store',
help = 'Bintray subject. Defaults to bt-user. For prod, '
'use "ycm-core"' )
parser.add_argument( '--bt-token', action='store',
help = 'Bintray api token. Defaults to environment '
'variable: YCMD_BINTRAY_API_TOKEN.' )
parser.add_argument( '--from-cache', action='store',
help = 'Use the clang packages from this dir. Useful '
'if releases.llvm.org is unreliable.' )
parser.add_argument( '--output-dir', action='store',
help = 'For testing, directory to put bundles in.' )
parser.add_argument( '--no-upload', action='store_true',
help = "For testing, just build the bundles; don't "
"upload to bintray. Useful with --output-dir." )
parser.add_argument( '--keep-temp', action='store_true',
help = "For testing, don't delete the temp dir" )
args = parser.parse_args()
if not args.bt_user:
if 'YCMD_BINTRAY_USERNAME' not in os.environ:
raise RuntimeError( 'ERROR: Must specify either --bt-user or '
'YCMD_BINTRAY_USERNAME in environment' )
args.bt_user = os.environ[ 'YCMD_BINTRAY_USERNAME' ]
if not args.bt_token:
if 'YCMD_BINTRAY_API_TOKEN' not in os.environ:
raise RuntimeError( 'ERROR: Must specify either --bt-token or '
'YCMD_BINTRAY_API_TOKEN in environment' )
args.bt_token = os.environ[ 'YCMD_BINTRAY_API_TOKEN' ]
if not args.bt_subject:
args.bt_subject = args.bt_user
return args
def PrepareBundleBuiltIn( extract_fun,
cache_dir,
llvm_package,
download_url,
temp_dir ):
package_dir = None
if cache_dir:
archive = os.path.join( cache_dir, llvm_package )
print( 'Extracting cached {}'.format( llvm_package ) )
try:
with open( archive, 'rb' ) as f:
package_dir = extract_fun( f.read(), temp_dir )
except IOError:
pass
if not package_dir:
compressed_data = Download( download_url )
if cache_dir:
try:
archive = os.path.join( cache_dir, llvm_package )
with open( archive, 'wb' ) as f:
f.write( compressed_data )
except IOError as e:
print( "Unable to write cache file: {}".format( e.message ) )
pass
print( 'Extracting {}'.format( llvm_package ) )
package_dir = extract_fun( compressed_data, temp_dir )
return package_dir
def PrepareBundleLZMA( cache_dir, llvm_package, download_url, temp_dir ):
return PrepareBundleBuiltIn( ExtractLZMA,
cache_dir,
llvm_package,
download_url,
temp_dir )
def PrepareBundleGZIP( cache_dir, llvm_package, download_url, temp_dir ):
return PrepareBundleBuiltIn( ExtractGZIP,
cache_dir,
llvm_package,
download_url,
temp_dir )
def PrepareBundleNSIS( cache_dir, llvm_package, download_url, temp_dir ):
archive = None
if cache_dir:
archive = os.path.join( cache_dir, llvm_package )
if os.path.exists( archive ):
print( 'Extracting cached {}'.format( llvm_package ) )
else:
archive = None
if not archive:
compressed_data = Download( download_url )
dest_dir = cache_dir if cache_dir else temp_dir
archive = os.path.join( dest_dir, llvm_package )
with open( archive, 'wb' ) as f:
f.write( compressed_data )
print( 'Extracting {}'.format( llvm_package ) )
return Extract7Z( llvm_package, archive, temp_dir )
def BundleAndUpload( args, temp_dir, output_dir, os_name, download_data,
license_file_name, hashes ):
llvm_package = download_data[ 'llvm_package' ].format(
os_name = os_name,
llvm_version = args.version )
download_url = download_data[ 'url' ].format( llvm_version = args.version,
llvm_package = llvm_package )
temp_dir = os.path.join( temp_dir, os_name )
os.makedirs( temp_dir )
try:
if download_data[ 'format' ] == 'lzma':
package_dir = PrepareBundleLZMA( args.from_cache,
llvm_package,
download_url,
temp_dir )
elif download_data[ 'format' ] == 'nsis':
package_dir = PrepareBundleNSIS( args.from_cache,
llvm_package,
download_url,
temp_dir )
elif download_data[ 'format' ] == 'gzip':
package_dir = PrepareBundleGZIP( args.from_cache,
llvm_package,
download_url,
temp_dir )
else:
raise AssertionError( 'Format not yet implemented: {}'.format(
download_data[ 'format' ] ) )
except requests.exceptions.HTTPError as error:
if error.response.status_code != 404:
raise
print( 'Cannot download {}'.format( llvm_package ) )
return
for binary in [ 'libclang', 'clangd' ]:
package_name = binary + '_package'
archive_name = download_data[ package_name ][ 'name' ].format(
os_name = os_name,
llvm_version = args.version )
archive_path = os.path.join( output_dir, archive_name )
if 'run_after_extract' in download_data[ package_name ]:
extra_cmd = download_data[ package_name ][ 'run_after_extract' ]
extra_cmd( package_dir, args.version )
MakeBundle( download_data[ package_name ][ 'files_to_copy' ],
license_file_name,
package_dir,
archive_path,
hashes,
args.version )
if not args.no_upload:
UploadBundleToBintray( args.bt_user,
args.bt_token,
args.bt_subject,
os_name,
args.version,
archive_path )
def Overwrite( src, dest ):
if os.path.exists( dest ):
shutil.rmtree( dest )
shutil.copytree( src, dest )
def UpdateClangHeaders( args, temp_dir ):
src_name = 'cfe-{version}.src'.format( version = args.version )
archive_name = src_name + '.tar.xz'
compressed_data = Download( 'https://releases.llvm.org/{version}/'
'{archive}'.format( version = args.version,
archive = archive_name ) )
print( 'Extracting {}'.format( archive_name ) )
src = ExtractLZMA( compressed_data, temp_dir )
print( 'Updating Clang headers...' )
includes_dir = os.path.join(
DIR_OF_THIRD_PARTY, 'clang', 'lib', 'clang', args.version, 'include' )
Overwrite( os.path.join( src, 'lib', 'Headers' ), includes_dir )
os.remove( os.path.join( includes_dir, 'CMakeLists.txt' ) )
Overwrite( os.path.join( src, 'include', 'clang-c' ),
os.path.join( DIR_OF_THIS_SCRIPT, 'cpp', 'llvm', 'include',
'clang-c' ) )
def Main():
args = ParseArguments()
output_dir = args.output_dir if args.output_dir else tempfile.mkdtemp()
try:
hashes = {}
with TemporaryDirectory( args.keep_temp ) as temp_dir:
license_file_name = DownloadClangLicense( args.version, temp_dir )
for os_name, download_data in LLVM_DOWNLOAD_DATA.items():
BundleAndUpload( args, temp_dir, output_dir, os_name, download_data,
license_file_name, hashes )
UpdateClangHeaders( args, temp_dir )
finally:
if not args.output_dir:
shutil.rmtree( output_dir )
for bundle_file_name, sha256 in hashes.items():
print( 'Checksum for {bundle_file_name}: {sha256}'.format(
bundle_file_name = bundle_file_name,
sha256 = sha256 ) )
if __name__ == "__main__":
Main()
1
https://gitee.com/zhuixixi/ycmd.git
git@gitee.com:zhuixixi/ycmd.git
zhuixixi
ycmd
ycmd
master

搜索帮助