1cb93a386Sopenharmony_ci#!/usr/bin/env python
2cb93a386Sopenharmony_ci# Copyright (c) 2012 The Chromium Authors. All rights reserved.
3cb93a386Sopenharmony_ci# Use of this source code is governed by a BSD-style license that can be
4cb93a386Sopenharmony_ci# found in the LICENSE file.
5cb93a386Sopenharmony_ci
6cb93a386Sopenharmony_ci
7cb93a386Sopenharmony_ci"""Module that sanitizes source files with specified modifiers."""
8cb93a386Sopenharmony_ci
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_cifrom __future__ import print_function
11cb93a386Sopenharmony_ciimport commands
12cb93a386Sopenharmony_ciimport os
13cb93a386Sopenharmony_ciimport sys
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_ci_FILE_EXTENSIONS_TO_SANITIZE = ['cpp', 'h', 'c']
17cb93a386Sopenharmony_ci
18cb93a386Sopenharmony_ci_SUBDIRS_TO_IGNORE = ['.git', '.svn', 'third_party']
19cb93a386Sopenharmony_ci
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_cidef SanitizeFilesWithModifiers(directory, file_modifiers, line_modifiers):
22cb93a386Sopenharmony_ci  """Sanitizes source files with the specified file and line modifiers.
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_ci  Args:
25cb93a386Sopenharmony_ci    directory: string - The directory which will be recursively traversed to
26cb93a386Sopenharmony_ci        find source files to apply modifiers to.
27cb93a386Sopenharmony_ci    file_modifiers: list - file-modification methods which should be applied to
28cb93a386Sopenharmony_ci        the complete file content (Eg: EOFOneAndOnlyOneNewlineAdder).
29cb93a386Sopenharmony_ci    line_modifiers: list - line-modification methods which should be applied to
30cb93a386Sopenharmony_ci        lines in a file (Eg: TabReplacer).
31cb93a386Sopenharmony_ci  """
32cb93a386Sopenharmony_ci  for item in os.listdir(directory):
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_ci    full_item_path = os.path.join(directory, item)
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ci    if os.path.isfile(full_item_path):  # Item is a file.
37cb93a386Sopenharmony_ci
38cb93a386Sopenharmony_ci      # Only sanitize files with extensions we care about.
39cb93a386Sopenharmony_ci      if (len(full_item_path.split('.')) > 1 and
40cb93a386Sopenharmony_ci          full_item_path.split('.')[-1] in _FILE_EXTENSIONS_TO_SANITIZE):
41cb93a386Sopenharmony_ci        f = file(full_item_path)
42cb93a386Sopenharmony_ci        try:
43cb93a386Sopenharmony_ci          lines = f.readlines()
44cb93a386Sopenharmony_ci        finally:
45cb93a386Sopenharmony_ci          f.close()
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_ci        new_lines = []  # Collect changed lines here.
48cb93a386Sopenharmony_ci        line_number = 0  # Keeps track of line numbers in the source file.
49cb93a386Sopenharmony_ci        write_to_file = False  # File is written to only if this flag is set.
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_ci        # Run the line modifiers for each line in this file.
52cb93a386Sopenharmony_ci        for line in lines:
53cb93a386Sopenharmony_ci          original_line = line
54cb93a386Sopenharmony_ci          line_number += 1
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ci          for modifier in line_modifiers:
57cb93a386Sopenharmony_ci            line = modifier(line, full_item_path, line_number)
58cb93a386Sopenharmony_ci            if original_line != line:
59cb93a386Sopenharmony_ci              write_to_file = True
60cb93a386Sopenharmony_ci          new_lines.append(line)
61cb93a386Sopenharmony_ci
62cb93a386Sopenharmony_ci        # Run the file modifiers.
63cb93a386Sopenharmony_ci        old_content = ''.join(lines)
64cb93a386Sopenharmony_ci        new_content = ''.join(new_lines)
65cb93a386Sopenharmony_ci        for modifier in file_modifiers:
66cb93a386Sopenharmony_ci          new_content = modifier(new_content, full_item_path)
67cb93a386Sopenharmony_ci        if new_content != old_content:
68cb93a386Sopenharmony_ci          write_to_file = True
69cb93a386Sopenharmony_ci
70cb93a386Sopenharmony_ci        # Write modifications to the file.
71cb93a386Sopenharmony_ci        if write_to_file:
72cb93a386Sopenharmony_ci          f = file(full_item_path, 'w')
73cb93a386Sopenharmony_ci          try:
74cb93a386Sopenharmony_ci            f.write(new_content)
75cb93a386Sopenharmony_ci          finally:
76cb93a386Sopenharmony_ci            f.close()
77cb93a386Sopenharmony_ci          print('Made changes to %s' % full_item_path)
78cb93a386Sopenharmony_ci
79cb93a386Sopenharmony_ci    elif item not in _SUBDIRS_TO_IGNORE:
80cb93a386Sopenharmony_ci      # Item is a directory recursively call the method.
81cb93a386Sopenharmony_ci      SanitizeFilesWithModifiers(full_item_path, file_modifiers, line_modifiers)
82cb93a386Sopenharmony_ci
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_ci############## Line Modification methods ##############
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_ci
87cb93a386Sopenharmony_cidef TrailingWhitespaceRemover(line, file_path, line_number):
88cb93a386Sopenharmony_ci  """Strips out trailing whitespaces from the specified line."""
89cb93a386Sopenharmony_ci  stripped_line = line.rstrip() + '\n'
90cb93a386Sopenharmony_ci  if line != stripped_line:
91cb93a386Sopenharmony_ci    print('Removing trailing whitespace in %s:%s' % (file_path, line_number))
92cb93a386Sopenharmony_ci  return stripped_line
93cb93a386Sopenharmony_ci
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_cidef CrlfReplacer(line, file_path, line_number):
96cb93a386Sopenharmony_ci  """Replaces CRLF with LF."""
97cb93a386Sopenharmony_ci  if '\r\n' in line:
98cb93a386Sopenharmony_ci    print('Replacing CRLF with LF in %s:%s' % (file_path, line_number))
99cb93a386Sopenharmony_ci  return line.replace('\r\n', '\n')
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ci
102cb93a386Sopenharmony_cidef TabReplacer(line, file_path, line_number):
103cb93a386Sopenharmony_ci  """Replaces Tabs with 4 whitespaces."""
104cb93a386Sopenharmony_ci  if '\t' in line:
105cb93a386Sopenharmony_ci    print('Replacing Tab with whitespace in %s:%s' % (file_path, line_number))
106cb93a386Sopenharmony_ci  return line.replace('\t', '    ')
107cb93a386Sopenharmony_ci
108cb93a386Sopenharmony_ci
109cb93a386Sopenharmony_ci############## File Modification methods ##############
110cb93a386Sopenharmony_ci
111cb93a386Sopenharmony_ci
112cb93a386Sopenharmony_cidef CopywriteChecker(file_content, unused_file_path):
113cb93a386Sopenharmony_ci  """Ensures that the copywrite information is correct."""
114cb93a386Sopenharmony_ci  # TODO(rmistry): Figure out the legal implications of changing old copyright
115cb93a386Sopenharmony_ci  # headers.
116cb93a386Sopenharmony_ci  return file_content
117cb93a386Sopenharmony_ci
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_cidef EOFOneAndOnlyOneNewlineAdder(file_content, file_path):
120cb93a386Sopenharmony_ci  """Adds one and only one LF at the end of the file."""
121cb93a386Sopenharmony_ci  if file_content and (file_content[-1] != '\n' or file_content[-2:-1] == '\n'):
122cb93a386Sopenharmony_ci    file_content = file_content.rstrip()
123cb93a386Sopenharmony_ci    file_content += '\n'
124cb93a386Sopenharmony_ci    print('Added exactly one newline to %s' % file_path)
125cb93a386Sopenharmony_ci  return file_content
126cb93a386Sopenharmony_ci
127cb93a386Sopenharmony_ci
128cb93a386Sopenharmony_cidef SvnEOLChecker(file_content, file_path):
129cb93a386Sopenharmony_ci  """Sets svn:eol-style property to LF."""
130cb93a386Sopenharmony_ci  output = commands.getoutput(
131cb93a386Sopenharmony_ci      'svn propget svn:eol-style %s' % file_path)
132cb93a386Sopenharmony_ci  if output != 'LF':
133cb93a386Sopenharmony_ci    print('Setting svn:eol-style property to LF in %s' % file_path)
134cb93a386Sopenharmony_ci    os.system('svn ps svn:eol-style LF %s' % file_path)
135cb93a386Sopenharmony_ci  return file_content
136cb93a386Sopenharmony_ci
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_ci#######################################################
139cb93a386Sopenharmony_ci
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_ciif '__main__' == __name__:
142cb93a386Sopenharmony_ci  sys.exit(SanitizeFilesWithModifiers(
143cb93a386Sopenharmony_ci      os.getcwd(),
144cb93a386Sopenharmony_ci      file_modifiers=[
145cb93a386Sopenharmony_ci          CopywriteChecker,
146cb93a386Sopenharmony_ci          EOFOneAndOnlyOneNewlineAdder,
147cb93a386Sopenharmony_ci          SvnEOLChecker,
148cb93a386Sopenharmony_ci      ],
149cb93a386Sopenharmony_ci      line_modifiers=[
150cb93a386Sopenharmony_ci          CrlfReplacer,
151cb93a386Sopenharmony_ci          TabReplacer,
152cb93a386Sopenharmony_ci          TrailingWhitespaceRemover,
153cb93a386Sopenharmony_ci      ],
154cb93a386Sopenharmony_ci  ))
155