Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added source indexing for symbols #922

Merged
merged 8 commits into from
Feb 6, 2019
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 51 additions & 2 deletions buildscripts/builddrivers.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
import shutil
import os.path
import argparse
import subprocess
from buildtools import BuildUtil
from indexsymbols import *

class BuildDriver(object):
"""Build sqlsrv and/or pdo_sqlsrv drivers with PHP source with the following properties:
Expand All @@ -38,6 +40,8 @@ class BuildDriver(object):
make_clean # a boolean flag - whether make clean is necessary
source_path # path to a local source folder
testing # whether the user has turned on testing mode
srctool_path # path to source indexing tools (empty string by default)
tag_version # tag version for source indexing (empty string by default)
"""

def __init__(self, phpver, driver, arch, thread, debug, repo, branch, source, path, testing, no_rename):
Expand All @@ -49,6 +53,8 @@ def __init__(self, phpver, driver, arch, thread, debug, repo, branch, source, pa
self.testing = testing
self.rebuild = False
self.make_clean = False
self.srctool_path = ''
self.tag_version = ''

def show_config(self):
print()
Expand Down Expand Up @@ -112,6 +118,34 @@ def get_local_source(self, source_path):
print("The path provided is invalid. Please re-enter.")
return source

def index_all_symbols(self, ext_dir, srctool_path, tag_version):
"""This takes care of indexing all the symbols

:param ext_dir: the directory where we can find the built extension(s)
:param srctool_path: the path to the tools for source indexing
:param tag_version: tag version for source indexing
:outcome: all symbols will be source indexed
"""
work_dir = os.path.dirname(os.path.realpath(__file__))
os.chdir(srctool_path)

if self.util.driver == 'all':
driver = 'sqlsrv'
pdbfile = os.path.join(ext_dir, self.util.driver_name(driver, '.pdb'))
print('Indexing this symbol: ', pdbfile)
run_indexing_tools(pdbfile, driver, tag_version)
driver = 'pdo_sqlsrv'
pdbfile = os.path.join(ext_dir, self.util.driver_name(driver, '.pdb'))
print('Indexing this symbol: ', pdbfile)
run_indexing_tools(pdbfile, driver, tag_version)
else:
driver = self.util.driver
pdbfile = os.path.join(ext_dir, self.util.driver_name(driver, '.pdb'))
print('Indexing this symbol: ', pdbfile)
run_indexing_tools(pdbfile, driver, tag_version)

os.chdir(work_dir)

def build_extensions(self, root_dir, logfile):
"""This takes care of getting the drivers' source files, building the drivers.
If dest_path is defined, the binaries will be copied to the designated destinations.
Expand Down Expand Up @@ -151,6 +185,12 @@ def build_extensions(self, root_dir, logfile):
# ext_dir is the directory where we can find the built extension(s)
ext_dir = self.util.build_drivers(self.make_clean, dest, logfile)

# Do source indexing only if the tag and tools path are both specified
if self.tag_version is not '' and self.srctool_path is not '':
print('Source indexing begins...')
self.index_all_symbols(ext_dir, self.srctool_path, self.tag_version)
print('Source indexing done')

# Copy the binaries if a destination path is defined
if self.dest_path is not None:
dest_drivers = os.path.join(self.dest_path, self.util.major_version(), self.util.arch)
Expand All @@ -172,9 +212,12 @@ def build_extensions(self, root_dir, logfile):

return ext_dir

def build(self):
def build(self, srctool_path, tag_version):
"""This is the main entry point of building drivers for PHP.
For development, this will loop till the user decides to quit.

:param srctool_path: the path to the tools for source indexing
:param tag_version: tag version for source indexing
"""
self.show_config()

Expand All @@ -191,6 +234,10 @@ def build(self):

logfile = self.util.get_logfile_name()

# Save source indexing details
self.srctool_path = srctool_path
self.tag_version = tag_version

try:
ext_dir = self.build_extensions(root_dir, logfile)
print('Build Completed')
Expand Down Expand Up @@ -244,6 +291,8 @@ def validate_input(question, values):
parser.add_argument('--TESTING', action='store_true', help="turns on testing mode (default: False)")
parser.add_argument('--DESTPATH', default=None, help="an alternative destination for the drivers (default: None)")
parser.add_argument('--NO_RENAME', action='store_true', help="drivers will not be renamed(default: False)")
parser.add_argument('--SRCIDX_PATH', default='', help="the path to the tools for source indexing (default: '')")
parser.add_argument('--TAG_VERSION', default='', help="the tag version for source indexing (default: '')")

args = parser.parse_args()

Expand Down Expand Up @@ -305,4 +354,4 @@ def validate_input(question, values):
path,
testing,
no_rename)
builder.build()
builder.build(args.SRCIDX_PATH, args.TAG_VERSION)
3 changes: 1 addition & 2 deletions buildscripts/buildtools.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,6 @@ def build_drivers(self, make_clean = False, dest = None, log_file = None):
is complete.
"""
work_dir = os.path.dirname(os.path.realpath(__file__))

# First, update the driver source file contents
source_dir = os.path.join(work_dir, 'Source')
if self.driver == 'all':
Expand Down Expand Up @@ -402,6 +401,7 @@ def build_drivers(self, make_clean = False, dest = None, log_file = None):

# Final step, copy the binaries to the right place
ext_dir = self.copy_binaries(sdk_dir, copy_to_ext)

return ext_dir

def rename_binary(self, path, driver):
Expand Down Expand Up @@ -454,7 +454,6 @@ def copy_binaries(self, sdk_dir, copy_to_ext):
shutil.copy(os.path.join(phpsrc, 'php.ini-production'), php_ini_file)

# Copy run-tests.php as well
phpsrc = self.phpsrc_root(sdk_dir)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is no longer needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, see line 453

shutil.copy(os.path.join(phpsrc, 'run-tests.php'), build_dir)

print('Copying the binaries from', build_dir)
Expand Down
136 changes: 136 additions & 0 deletions buildscripts/indexsymbols.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#!/usr/bin/python3
#########################################################################################
#
# Description: This contains helper methods for source indexing
#
# Requirement:
# python 3.x
# srctool.exe and pdbstr.exe
#
#############################################################################################

import os.path
import argparse
import subprocess
from subprocess import Popen, PIPE

def write_index(index_filename, tag_version):
"""This writes to a temporary index file for later use

For example

SRCSRV: ini ------------------------------------------------
VERSION=1
SRCSRV: variables ------------------------------------------
PATH=%var2%
SRCSRVTRG=%TARG%\%PDBVERSION%\%fnbksl%(%var2%)
SRCURL=https://raw.githubusercontent.com/Microsoft/msphpsql/%SRCVERSION%/source/%PATH%
SRCSRVCMD=powershell -Command "$r=New-Object -ComObject Msxml2.XMLHTTP; $r.open('GET', '%SRCURL%', $false); $r.send(); [io.file]::WriteAllBytes('%SRCSRVTRG%', $r.responseBody)"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this command do? Is this the command that actually does the source indexing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This inserts the powershell command into individual source file in the pdb file such that when that source file is needed, it will be downloaded from the right place based on the url

SRCVERSION=v5.6.0
PDBVERSION=v5.6.0
For example
"""
with open(index_filename, 'w') as f:
f.write('SRCSRV: ini ------------------------------------------------\n')
f.write('VERSION=1\n')
f.write('SRCSRV: variables ------------------------------------------\n')
f.write('PATH=%var2%\n')
f.write('SRCSRVTRG=%TARG%\%PDBVERSION%\%fnbksl%(%var2%)\n')
f.write('SRCURL=https://raw.githubusercontent.com/Microsoft/msphpsql/%SRCVERSION%/source/%PATH%\n')
f.write('SRCSRVCMD=powershell -Command ')
f.write('\"$r=New-Object -ComObject Msxml2.XMLHTTP; ')
f.write('$r.open(\'GET\', \'%SRCURL%\', $false); ')
f.write('$r.send(); [io.file]::WriteAllBytes(\'%SRCSRVTRG%\', $r.responseBody)\"\n')
f.write('SRCVERSION=' + tag_version + '\n')
f.write('PDBVERSION=' + tag_version + '\n')

def append_source_filess(index_filename, source_files, driver):
"""This appends the paths to different source files to the temporary index file

For example

SRCSRV: source files ---------------------------------------
c:\php-sdk\phpdev\vc15\x86\php-7.2.14-src\ext\pdo_sqlsrv\pdo_dbh.cpp*pdo_sqlsrv/pdo_dbh.cpp
c:\php-sdk\phpdev\vc15\x86\php-7.2.14-src\ext\pdo_sqlsrv\pdo_init.cpp*pdo_sqlsrv/pdo_init.cpp
... ...
c:\php-sdk\phpdev\vc15\x86\php-7.2.14-src\ext\pdo_sqlsrv\shared\core_stream.cpp*shared/core_stream.cpp
c:\php-sdk\phpdev\vc15\x86\php-7.2.14-src\ext\pdo_sqlsrv\shared\core_util.cpp*shared/core_util.cpp
SRCSRV: end ------------------------------------------------
"""
failed = False
with open(index_filename, 'a') as idx_file:
idx_file.write('SRCSRV: source files ---------------------------------------\n')
with open(source_files, 'r') as src_file:
for line in src_file:
pos = line.find('shared')
if (pos > 0): # it's a nested folder, so it must be positive
relative_path = line[pos:]
src_line = line[:-1] + '*' + relative_path.replace('\\', '/')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line[:-1] is excluding the newline at the end?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

else: # not a file in the shared folder
pos = line.find(driver)
if (pos <= 0):
print('Something is wrong!!')
failed = True
break
else:
relative_path = line[pos:]
src_line = src_line = line[:-1] + '*' + relative_path.replace('\\', '/')
idx_file.write(src_line)
idx_file.write('SRCSRV: end ------------------------------------------------\n')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for os.linesep here?

return failed

def run_indexing_tools(pdbfile, driver, tag_version):
"""This invokes the source indexing tools

:param pdbfile: the absolute path to the symbol file
:param driver: either sqlsrv or pdo_sqlsrv
:param tag_version: tag version for source indexing
:outcome: the driver pdb file will be source indexed
"""
# run srctool.exe to get all driver's source files from the PDB file
# srctool.exe -r <PDBfile> | find "<driver>\" | sort > files.txt
batch_filename = 'runsrctool.bat'
index_filename = 'idx.txt'
source_files = 'files.txt'

with open(batch_filename, 'w') as batch_file:
batch_file.write('@ECHO OFF' + os.linesep)
batch_file.write('@CALL srctool -r %1 | find "%2\\" | sort > ' + source_files + ' 2>&1' + os.linesep)

get_source_filess = batch_filename + ' {0} {1} '
get_source_filess_cmd = get_source_filess.format(pdbfile, driver)
subprocess.call(get_source_filess_cmd)

# create an index file using the above inputs for pdbstr.exe
write_index(index_filename, tag_version)
failed = append_source_filess(index_filename, source_files, driver)

if failed:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be good to have an error message here?

exit(1)

# run pdbstr.exe to insert the information into the PDB file
# pdbstr.exe -w -p:<PDBfile> -i:idx.txt -s:srcsrv
pdbstr_str = 'pdbstr.exe -w -p:{0} -i:{1} -s:srcsrv'
pdbstr_cmd = pdbstr_str.format(pdbfile, index_filename)
subprocess.call(pdbstr_cmd)

os.remove(batch_filename)
os.remove(index_filename)
os.remove(source_files)

################################### Main Function ###################################
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('PDBFILE', help="the path to the pdb file for source indexing")
parser.add_argument('DRIVER', choices=['sqlsrv', 'pdo_sqlsrv'], help="driver name of this pdb file")
parser.add_argument('TAG_VERSION', help="the tag version for source indexing (e.g. v5.6.0)")
parser.add_argument('TOOLS_PATH',help="the path to the source indexing tools")

args = parser.parse_args()

work_dir = os.path.dirname(os.path.realpath(__file__))
os.chdir(args.TOOLS_PATH)

run_indexing_tools(args.PDBFILE, args.DRIVER.lower(), args.TAG_VERSION)

os.chdir(work_dir)