| 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 = getenv().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): |
||
| 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 |