| | 356 | ## Index that computes scores based on files and directories. |
|---|
| | 357 | ################################################################################ |
|---|
| | 358 | |
|---|
| | 359 | class OneOf(object): |
|---|
| | 360 | def __init__(self, *possibilities): |
|---|
| | 361 | self.possibilities = possibilities |
|---|
| | 362 | def __str__(self): |
|---|
| | 363 | return 'one of %s' % (self.possibilities,) |
|---|
| | 364 | |
|---|
| | 365 | def WithOptionalExt(name, extensions): |
|---|
| | 366 | """Handy way of writing Cheese rules for files with extensions. |
|---|
| | 367 | |
|---|
| | 368 | Instead of writing: |
|---|
| | 369 | >>> one_of = OneOf('readme', 'readme.html', 'readme.txt') |
|---|
| | 370 | |
|---|
| | 371 | Write this: |
|---|
| | 372 | >>> opt_ext = WithOptionalExt('readme', ['html', 'txt']) |
|---|
| | 373 | |
|---|
| | 374 | It means the same! (representation have a meaning) |
|---|
| | 375 | >>> str(one_of) == str(opt_ext) |
|---|
| | 376 | True |
|---|
| | 377 | """ |
|---|
| | 378 | possibilities = [name] |
|---|
| | 379 | possibilities.extend(map(lambda x: name + '.' + x, extensions)) |
|---|
| | 380 | |
|---|
| | 381 | return OneOf(*possibilities) |
|---|
| | 382 | |
|---|
| | 383 | def Doc(name): |
|---|
| | 384 | return WithOptionalExt(name, ['html', 'txt']) |
|---|
| | 385 | |
|---|
| | 386 | class FilesIndex(Index): |
|---|
| | 387 | _used_rules = [] |
|---|
| | 388 | |
|---|
| | 389 | def _compute_from_rules(self, files_list, package_dir, files_rules): |
|---|
| | 390 | self._used_rules = [] |
|---|
| | 391 | files_count = 0 |
|---|
| | 392 | value = 0 |
|---|
| | 393 | |
|---|
| | 394 | for filename in files_list: |
|---|
| | 395 | if not is_empty(os.path.join(package_dir, filename)): |
|---|
| | 396 | score = self.get_score(os.path.basename(filename), files_rules) |
|---|
| | 397 | if score != 0: |
|---|
| | 398 | value += score |
|---|
| | 399 | files_count += 1 |
|---|
| | 400 | |
|---|
| | 401 | return files_count, value |
|---|
| | 402 | |
|---|
| | 403 | def get_score(self, name, specs): |
|---|
| | 404 | for entry, value in specs.iteritems(): |
|---|
| | 405 | if self.match_filename(name, entry): |
|---|
| | 406 | self.cheesecake.log.debug("%d points entry found: %s (%s)" % \ |
|---|
| | 407 | (value, name, entry)) |
|---|
| | 408 | return value |
|---|
| | 409 | |
|---|
| | 410 | return 0 |
|---|
| | 411 | |
|---|
| | 412 | def match_filename(self, name, rule): |
|---|
| | 413 | """Check if `name` matches given `rule`. |
|---|
| | 414 | """ |
|---|
| | 415 | def equal(x, y): |
|---|
| | 416 | x_root, x_ext = os.path.splitext(x) |
|---|
| | 417 | y_root, y_ext = os.path.splitext(y.lower()) |
|---|
| | 418 | if x_root in [y_root.lower(), y_root.upper(), y_root.capitalize()] \ |
|---|
| | 419 | and x_ext in [y_ext.lower(), y_ext.upper()]: |
|---|
| | 420 | return True |
|---|
| | 421 | return False |
|---|
| | 422 | |
|---|
| | 423 | if rule in self._used_rules: |
|---|
| | 424 | return False |
|---|
| | 425 | |
|---|
| | 426 | if isinstance(rule, basestring): |
|---|
| | 427 | if equal(name, rule): |
|---|
| | 428 | self._used_rules.append(rule) |
|---|
| | 429 | return True |
|---|
| | 430 | elif isinstance(rule, OneOf): |
|---|
| | 431 | for poss in rule.possibilities: |
|---|
| | 432 | if self.match_filename(name, poss): |
|---|
| | 433 | self._used_rules.append(rule) |
|---|
| | 434 | return True |
|---|
| | 435 | |
|---|
| | 436 | return False |
|---|
| | 437 | |
|---|
| | 438 | ################################################################################ |
|---|
| 469 | | def match_filename(name, rule): |
|---|
| 470 | | """Check if `name` matches given `rule`. |
|---|
| 471 | | """ |
|---|
| 472 | | def equal(x, y): |
|---|
| 473 | | x_root, x_ext = os.path.splitext(x) |
|---|
| 474 | | y_root, y_ext = os.path.splitext(y.lower()) |
|---|
| 475 | | if x_root in [y_root.lower(), y_root.upper(), y_root.capitalize()] \ |
|---|
| 476 | | and x_ext in [y_ext.lower(), y_ext.upper()]: |
|---|
| 477 | | return True |
|---|
| 478 | | return False |
|---|
| 479 | | |
|---|
| 480 | | if isinstance(rule, basestring): |
|---|
| 481 | | if equal(name, rule): |
|---|
| 482 | | return True |
|---|
| 483 | | elif isinstance(rule, OneOf) and not rule.used: |
|---|
| 484 | | for poss in rule.possibilities: |
|---|
| 485 | | if match_filename(name, poss): |
|---|
| 486 | | rule.used = True |
|---|
| 487 | | return True |
|---|
| 488 | | |
|---|
| 489 | | return False |
|---|
| 490 | | |
|---|
| 491 | | class OneOf(object): |
|---|
| 492 | | def __init__(self, *possibilities): |
|---|
| 493 | | self.possibilities = possibilities |
|---|
| 494 | | self.used = False |
|---|
| 495 | | def __str__(self): |
|---|
| 496 | | return 'one of %s' % (self.possibilities,) |
|---|
| 497 | | |
|---|
| 498 | | def WithOptionalExt(name, extensions): |
|---|
| 499 | | """Handy way of writing Cheese rules for files with extensions. |
|---|
| 500 | | |
|---|
| 501 | | Instead of writing: |
|---|
| 502 | | >>> one_of = OneOf('readme', 'readme.html', 'readme.txt') |
|---|
| 503 | | |
|---|
| 504 | | Write this: |
|---|
| 505 | | >>> opt_ext = WithOptionalExt('readme', ['html', 'txt']) |
|---|
| 506 | | |
|---|
| 507 | | It means the same! (representation have a meaning) |
|---|
| 508 | | >>> str(one_of) == str(opt_ext) |
|---|
| 509 | | True |
|---|
| 510 | | """ |
|---|
| 511 | | possibilities = [name] |
|---|
| 512 | | possibilities.extend(map(lambda x: name + '.' + x, extensions)) |
|---|
| 513 | | |
|---|
| 514 | | return OneOf(*possibilities) |
|---|
| 515 | | |
|---|
| 516 | | def Doc(name): |
|---|
| 517 | | return WithOptionalExt(name, ['html', 'txt']) |
|---|
| 518 | | |
|---|
| 519 | | class IndexRequiredFiles(Index): |
|---|
| | 571 | class IndexRequiredFiles(FilesIndex): |
|---|
| 536 | | 'demo': 20, |
|---|
| 537 | | OneOf('doc', 'docs'): 25, |
|---|
| 538 | | OneOf('example', 'examples'): 20, |
|---|
| 539 | | OneOf('test', 'tests'): 25, |
|---|
| | 587 | OneOf('doc', 'docs'): 30, |
|---|
| | 588 | OneOf('test', 'tests'): 30, |
|---|
| | 589 | |
|---|
| | 590 | 'demo': 10, |
|---|
| | 591 | OneOf('example', 'examples'): 10, |
|---|
| 545 | | self.value = 0 |
|---|
| 546 | | self.reset_rules(self.cheese_files.keys() + self.cheese_dirs.keys()) |
|---|
| 547 | | |
|---|
| 548 | | files_count = 0 |
|---|
| 549 | | for filename in files_list: |
|---|
| 550 | | if not is_empty(os.path.join(package_dir, filename)): |
|---|
| 551 | | score = self.get_score(os.path.basename(filename), self.cheese_files) |
|---|
| 552 | | if score != 0: |
|---|
| 553 | | self.value += score |
|---|
| 554 | | files_count += 1 |
|---|
| 555 | | |
|---|
| 556 | | directories_count = 0 |
|---|
| 557 | | for directory in dirs_list: |
|---|
| 558 | | if not is_empty(os.path.join(package_dir, directory)): |
|---|
| 559 | | score = self.get_score(os.path.basename(directory), self.cheese_dirs) |
|---|
| 560 | | if score != 0: |
|---|
| 561 | | self.value += score |
|---|
| 562 | | directories_count += 1 |
|---|
| | 597 | files_count, files_value = self._compute_from_rules(files_list, package_dir, self.cheese_files) |
|---|
| | 598 | dirs_count, dirs_value = self._compute_from_rules(dirs_list, package_dir, self.cheese_dirs) |
|---|
| | 599 | |
|---|
| | 600 | self.value = files_value + dirs_value |
|---|
| 568 | | |
|---|
| 569 | | def get_score(self, name, specs): |
|---|
| 570 | | for entry, value in specs.iteritems(): |
|---|
| 571 | | if match_filename(name, entry): |
|---|
| 572 | | self.cheesecake.log.debug("%d points entry found: %s (%s)" % \ |
|---|
| 573 | | (value, name, entry)) |
|---|
| 574 | | return value |
|---|
| 575 | | |
|---|
| 576 | | return 0 |
|---|
| 577 | | |
|---|
| 578 | | def reset_rules(self, rules): |
|---|
| 579 | | if isinstance(rules, basestring): |
|---|
| 580 | | pass |
|---|
| 581 | | elif isiterable(rules): |
|---|
| 582 | | for rule in rules: |
|---|
| 583 | | self.reset_rules(rule) |
|---|
| 584 | | elif isinstance(rules, OneOf): |
|---|
| 585 | | rules.used = False |
|---|
| 586 | | self.reset_rules(rules.possibilities) |
|---|