def test_trace_symlink(self): expected = { 'root': { 'children': [], 'command': [ self.executable, os.path.join('trace_inputs', 'symlink.py'), ], 'executable': self.real_executable, 'files': [ { 'mode': MODE_R, 'path': os.path.join(REL_DATA, 'files2', 'bar'), 'size': self._size(REL_DATA, 'files2', 'bar'), }, { 'mode': MODE_R, 'path': os.path.join(REL_DATA, 'files2', 'foo'), 'size': self._size(REL_DATA, 'files2', 'foo'), }, { 'mode': MODE_R, 'path': os.path.join(REL_DATA, 'symlink.py'), 'size': self._size(REL_DATA, 'symlink.py'), }, ], 'initial_cwd': self.initial_cwd, }, } cmd = [sys.executable, os.path.join('trace_inputs', 'symlink.py')] results = self._execute_trace(cmd) actual = results.flatten() self.assertTrue(actual['root'].pop('pid')) self.assertEqual(expected, actual) files = [ # In particular, the symlink is *not* resolved. u'tests/trace_inputs/files2/'.replace('/', os.path.sep), u'tests/trace_inputs/symlink.py'.replace('/', os.path.sep), ] def blacklist(f): return f.endswith(('.pyc', '.svn', 'do_not_care.txt')) simplified = trace_inputs.extract_directories( unicode(ROOT_DIR), results.files, blacklist) self.assertEqual(files, [f.path for f in simplified])
def generate_simplified(files, root_dir, variables, relative_cwd): """Generates a clean and complete .isolate 'variables' dictionary. Cleans up and extracts only files from within root_dir then processes variables and relative_cwd. """ # Constants. # Skip log in PRODUCT_DIR. Note that these are applied on '/' style path # separator. LOG_FILE = re.compile(r'^\<\(PRODUCT_DIR\)\/[^\/]+\.log$') EXECUTABLE = re.compile(r'^(\<\(PRODUCT_DIR\)\/[^\/\.]+)' + re.escape(variables.get('EXECUTABLE_SUFFIX', '')) + r'$') # Preparation work. relative_cwd = cleanup_path(relative_cwd) # Creates the right set of variables here. We only care about # PATH_VARIABLES. variables = dict( ('<(%s)' % k, variables[k]) for k in PATH_VARIABLES if k in variables) # Actual work: Process the files. files = trace_inputs.extract_directories(root_dir, files) files = (f.replace_variables(variables) for f in files) def fix(f): """Bases the file on the most restrictive variable.""" logging.debug('fix(%s)' % f) # Important, GYP stores the files with / and not \. f = f.replace(os.path.sep, '/') # If it's not already a variable. if not f.startswith('<'): # relative_cwd is usually the directory containing the gyp file. It may be # empty if the whole directory containing the gyp file is needed. f = posix_relpath(f, relative_cwd) or './' # Now strips off known files we want to ignore and to any specific mangling # as necessary. It's easier to do it here than generate a blacklist. match = EXECUTABLE.match(f) if match: return match.group(1) + '<(EXECUTABLE_SUFFIX)' if LOG_FILE.match(f): return None return f return classify_files(filter(None, (fix(f.path) for f in files)))
def test_trace(self): expected = self._gen_dict_full_gyp() results = self._execute_trace(self.get_child_command(True)) actual = results.flatten() self.assertTrue(actual['root'].pop('pid')) self.assertTrue(actual['root']['children'][0].pop('pid')) self.assertEqual(expected, actual) files = [ u'tests/trace_inputs/child1.py'.replace('/', os.path.sep), u'tests/trace_inputs/child2.py'.replace('/', os.path.sep), u'tests/trace_inputs/files1/'.replace('/', os.path.sep), u'tests/trace_inputs/test_file.txt'.replace('/', os.path.sep), u'tests/trace_inputs_smoke_test.py'.replace('/', os.path.sep), u'trace_inputs.py', ] def blacklist(f): return f.endswith(('.pyc', 'do_not_care.txt', '.git', '.svn')) simplified = trace_inputs.extract_directories( file_path.get_native_path_case(unicode(ROOT_DIR)), results.files, blacklist) self.assertEqual(files, [f.path for f in simplified])
def generate_simplified(tracked, untracked, touched, root_dir, variables, relative_cwd): """Generates a clean and complete .isolate 'variables' dictionary. Cleans up and extracts only files from within root_dir then processes variables and relative_cwd. """ logging.info('generate_simplified(%d files, %s, %s, %s)' % (len(tracked) + len(untracked) + len(touched), root_dir, variables, relative_cwd)) # Constants. # Skip log in PRODUCT_DIR. Note that these are applied on '/' style path # separator. LOG_FILE = re.compile(r'^\<\(PRODUCT_DIR\)\/[^\/]+\.log$') EXECUTABLE = re.compile(r'^(\<\(PRODUCT_DIR\)\/[^\/\.]+)' + re.escape(variables.get('EXECUTABLE_SUFFIX', '')) + r'$') # Preparation work. relative_cwd = cleanup_path(relative_cwd) # Creates the right set of variables here. We only care about PATH_VARIABLES. variables = dict(('<(%s)' % k, variables[k].replace(os.path.sep, '/')) for k in PATH_VARIABLES if k in variables) # Actual work: Process the files. # TODO(maruel): if all the files in a directory are in part tracked and in # part untracked, the directory will not be extracted. Tracked files should be # 'promoted' to be untracked as needed. tracked = trace_inputs.extract_directories(root_dir, tracked, default_blacklist) untracked = trace_inputs.extract_directories(root_dir, untracked, default_blacklist) # touched is not compressed, otherwise it would result in files to be archived # that we don't need. def fix(f): """Bases the file on the most restrictive variable.""" logging.debug('fix(%s)' % f) # Important, GYP stores the files with / and not \. f = f.replace(os.path.sep, '/') # If it's not already a variable. if not f.startswith('<'): # relative_cwd is usually the directory containing the gyp file. It may be # empty if the whole directory containing the gyp file is needed. f = posix_relpath(f, relative_cwd) or './' for variable, root_path in variables.iteritems(): if f.startswith(root_path): f = variable + f[len(root_path):] break # Now strips off known files we want to ignore and to any specific mangling # as necessary. It's easier to do it here than generate a blacklist. match = EXECUTABLE.match(f) if match: return match.group(1) + '<(EXECUTABLE_SUFFIX)' if LOG_FILE.match(f): return None if sys.platform == 'darwin': # On OSX, the name of the output is dependent on gyp define, it can be # 'Google Chrome.app' or 'Chromium.app', same for 'XXX # Framework.framework'. Furthermore, they are versioned with a gyp # variable. To lower the complexity of the .isolate file, remove all the # individual entries that show up under any of the 4 entries and replace # them with the directory itself. Overall, this results in a bit more # files than strictly necessary. OSX_BUNDLES = ( '<(PRODUCT_DIR)/Chromium Framework.framework/', '<(PRODUCT_DIR)/Chromium.app/', '<(PRODUCT_DIR)/Google Chrome Framework.framework/', '<(PRODUCT_DIR)/Google Chrome.app/', ) for prefix in OSX_BUNDLES: if f.startswith(prefix): # Note this result in duplicate values, so the a set() must be used to # remove duplicates. return prefix return f tracked = set(filter(None, (fix(f.path) for f in tracked))) untracked = set(filter(None, (fix(f.path) for f in untracked))) touched = set(filter(None, (fix(f.path) for f in touched))) out = classify_files(root_dir, tracked, untracked) if touched: out[KEY_TOUCHED] = sorted(touched) return out
def generate_simplified(files, root_dir, variables, relative_cwd): """Generates a clean and complete .isolate 'variables' dictionary. Cleans up and extracts only files from within root_dir then processes variables and relative_cwd. """ logging.info( 'generate_simplified(%d files, %s, %s, %s)' % (len(files), root_dir, variables, relative_cwd)) # Constants. # Skip log in PRODUCT_DIR. Note that these are applied on '/' style path # separator. LOG_FILE = re.compile(r'^\<\(PRODUCT_DIR\)\/[^\/]+\.log$') EXECUTABLE = re.compile( r'^(\<\(PRODUCT_DIR\)\/[^\/\.]+)' + re.escape(variables.get('EXECUTABLE_SUFFIX', '')) + r'$') # Preparation work. relative_cwd = cleanup_path(relative_cwd) # Creates the right set of variables here. We only care about PATH_VARIABLES. variables = dict( ('<(%s)' % k, variables[k]) for k in PATH_VARIABLES if k in variables) # Actual work: Process the files. files = trace_inputs.extract_directories(root_dir, files, default_blacklist) def fix(f): """Bases the file on the most restrictive variable.""" logging.debug('fix(%s)' % f) # Important, GYP stores the files with / and not \. f = f.replace(os.path.sep, '/') # If it's not already a variable. if not f.startswith('<'): # relative_cwd is usually the directory containing the gyp file. It may be # empty if the whole directory containing the gyp file is needed. f = posix_relpath(f, relative_cwd) or './' for variable, root_path in variables.iteritems(): if f.startswith(root_path): f = variable + f[len(root_path):] break # Now strips off known files we want to ignore and to any specific mangling # as necessary. It's easier to do it here than generate a blacklist. match = EXECUTABLE.match(f) if match: return match.group(1) + '<(EXECUTABLE_SUFFIX)' if LOG_FILE.match(f): return None if sys.platform == 'darwin': # On OSX, the name of the output is dependent on gyp define, it can be # 'Google Chrome.app' or 'Chromium.app', same for 'XXX # Framework.framework'. Furthermore, they are versioned with a gyp # variable. To lower the complexity of the .isolate file, remove all the # individual entries that show up under any of the 4 entries and replace # them with the directory itself. Overall, this results in a bit more # files than strictly necessary. OSX_BUNDLES = ( '<(PRODUCT_DIR)/Chromium Framework.framework/', '<(PRODUCT_DIR)/Chromium.app/', '<(PRODUCT_DIR)/Google Chrome Framework.framework/', '<(PRODUCT_DIR)/Google Chrome.app/', ) for prefix in OSX_BUNDLES: if f.startswith(prefix): # Note this result in duplicate values, so the a set() must be used to # remove duplicates. return prefix return f return classify_files(set(filter(None, (fix(f.path) for f in files))))