| Conditions | 69 | 
| Total Lines | 207 | 
| Code Lines | 176 | 
| Lines | 0 | 
| Ratio | 0 % | 
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like exabgp.application.cli.cmdline() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | #!/usr/bin/env python  | 
            ||
| 113 | def cmdline(cmdarg):  | 
            ||
| 114 | pipename = env().api.pipename  | 
            ||
| 115 | |||
| 116 | command = cmdarg.command  | 
            ||
| 117 | |||
| 118 | pipes = named_pipe(ROOT, pipename)  | 
            ||
| 119 | if len(pipes) != 1:  | 
            ||
| 120 |         sys.stdout.write('could not find ExaBGP\'s named pipes (%s.in and %s.out) for the cli\n' % (pipename, pipename)) | 
            ||
| 121 |         sys.stdout.write('we scanned the following folders (the number is your PID):\n - ') | 
            ||
| 122 |         sys.stdout.write('\n - '.join(pipes)) | 
            ||
| 123 | sys.stdout.flush()  | 
            ||
| 124 | sys.exit(1)  | 
            ||
| 125 | |||
| 126 | send = pipes[0] + pipename + '.in'  | 
            ||
| 127 | recv = pipes[0] + pipename + '.out'  | 
            ||
| 128 | |||
| 129 | if not check_fifo(send):  | 
            ||
| 130 |         sys.stdout.write('could not find write named pipe to connect to ExaBGP') | 
            ||
| 131 | sys.stdout.flush()  | 
            ||
| 132 | sys.exit(1)  | 
            ||
| 133 | |||
| 134 | if not check_fifo(recv):  | 
            ||
| 135 |         sys.stdout.write('could not find read named pipe to connect to ExaBGP') | 
            ||
| 136 | sys.stdout.flush()  | 
            ||
| 137 | sys.exit(1)  | 
            ||
| 138 | |||
| 139 | reader = open_reader(recv)  | 
            ||
| 140 | |||
| 141 | rbuffer = b''  | 
            ||
| 142 | start = time.time()  | 
            ||
| 143 | while True:  | 
            ||
| 144 | try:  | 
            ||
| 145 | while select.select([reader], [], [], 0) != ([], [], []):  | 
            ||
| 146 | rbuffer += os.read(reader, 4096)  | 
            ||
| 147 | rbuffer = rbuffer[-AnswerStream.buffer_size :]  | 
            ||
| 148 | except IOError as exc:  | 
            ||
| 149 | if exc.errno in error.block:  | 
            ||
| 150 | continue  | 
            ||
| 151 |             sys.stdout.write('could not clear named pipe from potential previous command data (%s)' % str(exc)) | 
            ||
| 152 | sys.stdout.flush()  | 
            ||
| 153 | sys.exit(1)  | 
            ||
| 154 | except OSError as exc:  | 
            ||
| 155 | if exc.errno in error.block:  | 
            ||
| 156 | continue  | 
            ||
| 157 |             sys.stdout.write('could not clear named pipe from potential previous command data (%s)' % str(exc)) | 
            ||
| 158 | sys.stdout.write(exc)  | 
            ||
| 159 | sys.stdout.flush()  | 
            ||
| 160 | sys.exit(1)  | 
            ||
| 161 | |||
| 162 | # we are not ack'ing the command and probably have read all there is  | 
            ||
| 163 | if time.time() > start + 1.5:  | 
            ||
| 164 | break  | 
            ||
| 165 | |||
| 166 | # we read nothing, nothing to do  | 
            ||
| 167 | if not rbuffer:  | 
            ||
| 168 | break  | 
            ||
| 169 | |||
| 170 | # we read some data but it is not ending by a new line (ie: not a command completion)  | 
            ||
| 171 | if rbuffer[-1] != 10: # \n  | 
            ||
| 172 | continue  | 
            ||
| 173 | if AnswerStream.done.endswith(rbuffer[-len(AnswerStream.done) :]):  | 
            ||
| 174 | break  | 
            ||
| 175 | if AnswerStream.error.endswith(rbuffer[-len(AnswerStream.error) :]):  | 
            ||
| 176 | break  | 
            ||
| 177 | if AnswerStream.shutdown.endswith(rbuffer[-len(AnswerStream.shutdown) :]):  | 
            ||
| 178 | break  | 
            ||
| 179 | |||
| 180 | renamed = ['']  | 
            ||
| 181 | |||
| 182 | for pos, token in enumerate(command.split()):  | 
            ||
| 183 | for nickname, name, match in (  | 
            ||
| 184 |             ('a', 'announce', lambda pos, pre: pos == 0 or pre.count('.') == 3 or pre.count(':') != 0), | 
            ||
| 185 |             ('a', 'attributes', lambda pos, pre: pre[-1] == 'announce' or pre[-1] == 'withdraw'), | 
            ||
| 186 |             ('c', 'configuration', lambda pos, pre: True), | 
            ||
| 187 |             ('e', 'eor', lambda pos, pre: pre[-1] == 'announce'), | 
            ||
| 188 |             ('e', 'extensive', lambda _, pre: 'show' in pre), | 
            ||
| 189 |             ('f', 'flow', lambda pos, pre: pre[-1] == 'announce' or pre[-1] == 'withdraw'), | 
            ||
| 190 |             ('f', 'flush', lambda pos, pre: pos == 0 or pre.count('.') == 3 or pre.count(':') != 0), | 
            ||
| 191 |             ('h', 'help', lambda pos, pre: pos == 0), | 
            ||
| 192 |             ('i', 'in', lambda pos, pre: pre[-1] == 'adj-rib'), | 
            ||
| 193 |             ('n', 'neighbor', lambda pos, pre: pos == 0 or pre[-1] == 'show'), | 
            ||
| 194 |             ('r', 'route', lambda pos, pre: pre == 'announce' or pre == 'withdraw'), | 
            ||
| 195 |             ('rr', 'route-refresh', lambda _, pre: pre == 'announce'), | 
            ||
| 196 |             ('s', 'show', lambda pos, pre: pos == 0), | 
            ||
| 197 |             ('t', 'teardown', lambda pos, pre: pos == 0 or pre.count('.') == 3 or pre.count(':') != 0), | 
            ||
| 198 |             ('s', 'summary', lambda pos, pre: pos != 0), | 
            ||
| 199 |             ('v', 'vps', lambda pos, pre: pre[-1] == 'announce' or pre[-1] == 'withdraw'), | 
            ||
| 200 |             ('o', 'operation', lambda pos, pre: pre[-1] == 'announce'), | 
            ||
| 201 |             ('o', 'out', lambda pos, pre: pre[-1] == 'adj-rib'), | 
            ||
| 202 |             ('a', 'adj-rib', lambda pos, pre: pre[-1] in ['clear', 'flush', 'show']), | 
            ||
| 203 |             ('w', 'withdraw', lambda pos, pre: pos == 0 or pre.count('.') == 3 or pre.count(':') != 0), | 
            ||
| 204 |             ('w', 'watchdog', lambda pos, pre: pre[-1] == 'announce' or pre[-1] == 'withdraw'), | 
            ||
| 205 |             ('neighbour', 'neighbor', lambda pos, pre: True), | 
            ||
| 206 |             ('neigbour', 'neighbor', lambda pos, pre: True), | 
            ||
| 207 |             ('neigbor', 'neighbor', lambda pos, pre: True), | 
            ||
| 208 | ):  | 
            ||
| 209 | if (token == nickname or name.startswith(token)) and match(pos, renamed):  | 
            ||
| 210 | renamed.append(name)  | 
            ||
| 211 | break  | 
            ||
| 212 | else:  | 
            ||
| 213 | renamed.append(token)  | 
            ||
| 214 | |||
| 215 | sending = ' '.join(renamed).strip()  | 
            ||
| 216 | |||
| 217 | # This does not change the behaviour for well formed command  | 
            ||
| 218 | if sending != command:  | 
            ||
| 219 |         print('command: %s' % sending) | 
            ||
| 220 | |||
| 221 | writer = open_writer(send)  | 
            ||
| 222 | try:  | 
            ||
| 223 |         os.write(writer, sending.encode('utf-8') + b'\n') | 
            ||
| 224 | os.close(writer)  | 
            ||
| 225 | except IOError as exc:  | 
            ||
| 226 |         sys.stdout.write('could not send command to ExaBGP (%s)' % str(exc)) | 
            ||
| 227 | sys.stdout.flush()  | 
            ||
| 228 | sys.exit(1)  | 
            ||
| 229 | except OSError as exc:  | 
            ||
| 230 |         sys.stdout.write('could not send command to ExaBGP (%s)' % str(exc)) | 
            ||
| 231 | sys.stdout.flush()  | 
            ||
| 232 | sys.exit(1)  | 
            ||
| 233 | |||
| 234 | if command == 'reset':  | 
            ||
| 235 | sys.exit(0)  | 
            ||
| 236 | |||
| 237 | waited = 0.0  | 
            ||
| 238 | buf = b''  | 
            ||
| 239 | done = False  | 
            ||
| 240 | done_time_diff = 0.5  | 
            ||
| 241 | while not done:  | 
            ||
| 242 | try:  | 
            ||
| 243 | r, _, _ = select.select([reader], [], [], 0.01)  | 
            ||
| 244 | except OSError as exc:  | 
            ||
| 245 | if exc.errno in error.block:  | 
            ||
| 246 | continue  | 
            ||
| 247 |             sys.stdout.write('could not get answer from ExaBGP (%s)' % str(exc)) | 
            ||
| 248 | sys.stdout.flush()  | 
            ||
| 249 | sys.exit(1)  | 
            ||
| 250 | except IOError as exc:  | 
            ||
| 251 | if exc.errno in error.block:  | 
            ||
| 252 | continue  | 
            ||
| 253 |             sys.stdout.write('could not get answer from ExaBGP (%s)' % str(exc)) | 
            ||
| 254 | sys.stdout.flush()  | 
            ||
| 255 | sys.exit(1)  | 
            ||
| 256 | |||
| 257 | if waited > 5.0:  | 
            ||
| 258 |             sys.stderr.write('\n') | 
            ||
| 259 |             sys.stderr.write('warning: no end of command message received\n') | 
            ||
| 260 | sys.stderr.write(  | 
            ||
| 261 | 'warning: normal if exabgp.api.ack is set to false otherwise some data may get stuck on the pipe\n'  | 
            ||
| 262 | )  | 
            ||
| 263 |             sys.stderr.write('warning: otherwise it may cause exabgp reactor to block\n') | 
            ||
| 264 | sys.exit(0)  | 
            ||
| 265 | elif not r:  | 
            ||
| 266 | waited += 0.01  | 
            ||
| 267 | continue  | 
            ||
| 268 | else:  | 
            ||
| 269 | waited = 0.0  | 
            ||
| 270 | |||
| 271 | try:  | 
            ||
| 272 | raw = os.read(reader, 4096)  | 
            ||
| 273 | except OSError as exc:  | 
            ||
| 274 | if exc.errno in error.block:  | 
            ||
| 275 | continue  | 
            ||
| 276 |             sys.stdout.write('could not read answer from ExaBGP (%s)' % str(exc)) | 
            ||
| 277 | sys.stdout.flush()  | 
            ||
| 278 | sys.exit(1)  | 
            ||
| 279 | except IOError as exc:  | 
            ||
| 280 | if exc.errno in error.block:  | 
            ||
| 281 | continue  | 
            ||
| 282 |             sys.stdout.write('could not read answer from ExaBGP (%s)' % str(exc)) | 
            ||
| 283 | sys.stdout.flush()  | 
            ||
| 284 | sys.exit(1)  | 
            ||
| 285 | |||
| 286 | buf += raw  | 
            ||
| 287 | while b'\n' in buf:  | 
            ||
| 288 | line, buf = buf.split(b'\n', 1)  | 
            ||
| 289 | string = line.decode()  | 
            ||
| 290 | if string == Answer.done:  | 
            ||
| 291 | done = True  | 
            ||
| 292 | break  | 
            ||
| 293 | if string == Answer.shutdown:  | 
            ||
| 294 |                 sys.stderr.write('ExaBGP is shutting down, command aborted\n') | 
            ||
| 295 | sys.stderr.flush()  | 
            ||
| 296 | done = True  | 
            ||
| 297 | break  | 
            ||
| 298 | if string == Answer.error:  | 
            ||
| 299 | done = True  | 
            ||
| 300 |                 sys.stderr.write('ExaBGP returns an error (see ExaBGP\'s logs for more information)\n') | 
            ||
| 301 |                 sys.stderr.write('use help for a list of available commands\n') | 
            ||
| 302 | sys.stderr.flush()  | 
            ||
| 303 | break  | 
            ||
| 304 |             sys.stdout.write('%s\n' % string) | 
            ||
| 305 | sys.stdout.flush()  | 
            ||
| 306 | |||
| 307 | if not getenv().api.ack and not raw.decode():  | 
            ||
| 308 | this_moment = time.time()  | 
            ||
| 309 | recv_epoch_time = os.path.getmtime(recv)  | 
            ||
| 310 | time_diff = this_moment - recv_epoch_time  | 
            ||
| 311 | if time_diff >= done_time_diff:  | 
            ||
| 312 | done = True  | 
            ||
| 313 | |||
| 314 | try:  | 
            ||
| 315 | os.close(reader)  | 
            ||
| 316 | except Exception:  | 
            ||
| 317 | pass  | 
            ||
| 318 | |||
| 319 | sys.exit(0)  | 
            ||
| 320 | |||
| 327 |