|
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
|
2 # Use of this source code is governed by a BSD-style license that can be |
|
3 # found in the LICENSE file. |
|
4 |
|
5 import constants |
|
6 import traceback |
|
7 import warnings |
|
8 |
|
9 |
|
10 # Location where chrome reads command line flags from |
|
11 CHROME_COMMAND_FILE = constants.TEST_EXECUTABLE_DIR + '/chrome-command-line' |
|
12 |
|
13 class FlagChanger(object): |
|
14 """Changes the flags Chrome runs with. |
|
15 |
|
16 There are two different use cases for this file: |
|
17 * Flags are permanently set by calling Set(). |
|
18 * Flags can be temporarily set for a particular set of unit tests. These |
|
19 tests should call Restore() to revert the flags to their original state |
|
20 once the tests have completed. |
|
21 """ |
|
22 |
|
23 def __init__(self, android_cmd): |
|
24 self._android_cmd = android_cmd |
|
25 |
|
26 # Save the original flags. |
|
27 self._orig_line = self._android_cmd.GetFileContents(CHROME_COMMAND_FILE) |
|
28 if self._orig_line: |
|
29 self._orig_line = self._orig_line[0].strip() |
|
30 |
|
31 # Parse out the flags into a list to facilitate adding and removing flags. |
|
32 self._current_flags = self._TokenizeFlags(self._orig_line) |
|
33 |
|
34 def Get(self): |
|
35 """Returns list of current flags.""" |
|
36 return self._current_flags |
|
37 |
|
38 def Set(self, flags): |
|
39 """Replaces all flags on the current command line with the flags given. |
|
40 |
|
41 Args: |
|
42 flags: A list of flags to set, eg. ['--single-process']. |
|
43 """ |
|
44 if flags: |
|
45 assert flags[0] != 'chrome' |
|
46 |
|
47 self._current_flags = flags |
|
48 self._UpdateCommandLineFile() |
|
49 |
|
50 def AddFlags(self, flags): |
|
51 """Appends flags to the command line if they aren't already there. |
|
52 |
|
53 Args: |
|
54 flags: A list of flags to add on, eg. ['--single-process']. |
|
55 """ |
|
56 if flags: |
|
57 assert flags[0] != 'chrome' |
|
58 |
|
59 # Avoid appending flags that are already present. |
|
60 for flag in flags: |
|
61 if flag not in self._current_flags: |
|
62 self._current_flags.append(flag) |
|
63 self._UpdateCommandLineFile() |
|
64 |
|
65 def RemoveFlags(self, flags): |
|
66 """Removes flags from the command line, if they exist. |
|
67 |
|
68 Args: |
|
69 flags: A list of flags to remove, eg. ['--single-process']. Note that we |
|
70 expect a complete match when removing flags; if you want to remove |
|
71 a switch with a value, you must use the exact string used to add |
|
72 it in the first place. |
|
73 """ |
|
74 if flags: |
|
75 assert flags[0] != 'chrome' |
|
76 |
|
77 for flag in flags: |
|
78 if flag in self._current_flags: |
|
79 self._current_flags.remove(flag) |
|
80 self._UpdateCommandLineFile() |
|
81 |
|
82 def Restore(self): |
|
83 """Restores the flags to their original state.""" |
|
84 self._current_flags = self._TokenizeFlags(self._orig_line) |
|
85 self._UpdateCommandLineFile() |
|
86 |
|
87 def _UpdateCommandLineFile(self): |
|
88 """Writes out the command line to the file, or removes it if empty.""" |
|
89 print "Current flags: ", self._current_flags |
|
90 |
|
91 if self._current_flags: |
|
92 self._android_cmd.SetFileContents(CHROME_COMMAND_FILE, |
|
93 'chrome ' + |
|
94 ' '.join(self._current_flags)) |
|
95 else: |
|
96 self._android_cmd.RunShellCommand('rm ' + CHROME_COMMAND_FILE) |
|
97 |
|
98 def _TokenizeFlags(self, line): |
|
99 """Changes the string containing the command line into a list of flags. |
|
100 |
|
101 Follows similar logic to CommandLine.java::tokenizeQuotedArguments: |
|
102 * Flags are split using whitespace, unless the whitespace is within a |
|
103 pair of quotation marks. |
|
104 * Unlike the Java version, we keep the quotation marks around switch |
|
105 values since we need them to re-create the file when new flags are |
|
106 appended. |
|
107 |
|
108 Args: |
|
109 line: A string containing the entire command line. The first token is |
|
110 assumed to be the program name. |
|
111 """ |
|
112 if not line: |
|
113 return [] |
|
114 |
|
115 tokenized_flags = [] |
|
116 current_flag = "" |
|
117 within_quotations = False |
|
118 |
|
119 # Move through the string character by character and build up each flag |
|
120 # along the way. |
|
121 for c in line.strip(): |
|
122 if c is '"': |
|
123 if len(current_flag) > 0 and current_flag[-1] == '\\': |
|
124 # Last char was a backslash; pop it, and treat this " as a literal. |
|
125 current_flag = current_flag[0:-1] + '"' |
|
126 else: |
|
127 within_quotations = not within_quotations |
|
128 current_flag += c |
|
129 elif not within_quotations and (c is ' ' or c is '\t'): |
|
130 if current_flag is not "": |
|
131 tokenized_flags.append(current_flag) |
|
132 current_flag = "" |
|
133 else: |
|
134 current_flag += c |
|
135 |
|
136 # Tack on the last flag. |
|
137 if not current_flag: |
|
138 if within_quotations: |
|
139 warnings.warn("Unterminated quoted string: " + current_flag) |
|
140 else: |
|
141 tokenized_flags.append(current_flag) |
|
142 |
|
143 # Return everything but the program name. |
|
144 return tokenized_flags[1:] |