#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2013-2023 Edgewall Software
# Copyright (C) 2013 Christian Boos <cboos@edgewall.org>
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at https://trac.edgewall.org/wiki/TracLicense.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at https://trac.edgewall.org/.

"""

L10N tool which prepares an index of "interesting" changes found in a
.diff.

Skipped changes are:
 - the changes for which the msgid has changed
 - removal only of msgstr content


Example workflow 1), review changes to the 'fr' translation before
committing:

  make diff-fr | less


Example workflow 2), force a pull of all changes from Transifex::

  make update updateopts=-N
  tx pull -f
  make update updateopts=-N
  svn diff > tx.diff
  python l10n_diff_index.py tx.diff
  svn revert -R .

And then use either::

  emacs tx.diff.index --eval '(grep-mode)'

or::

  vim -c :cbuffer -c :copen tx.diff.index

This makes it easier to go through the potentially interesting changes
only, and apply the corresponding chunks if needed.

"""

from bisect import bisect_left
import re

interesting_changes_re = re.compile(r'''
                                               \n
       \s (?: msgid(?:_plural)?\s)? ".*"       \n  # ' ' msgid or "...",
   (?:
       [-\s]  ".*"                             \n  # ' ' or - "...",
   |
       -      msgstr(?:\[\d+\])? \s ".*"       \n  # or the -msgstr
   )*

 (?:
     ( \+     msgstr(?:\[\d+\])? \s "[^"].*" ) \n  # \1 is a non-empty +msgstr
 |
       [+\s]  msgstr(?:\[\d+\])? \s ".*"       \n  # or after the msgstr,
   (?: [-\s]  ".*"                             \n  # optional ' ' or -"...",
   )*
     ( \+     "[^"].*" )                           # \2 is a non-empty +"..."
 )
''', re.MULTILINE | re.VERBOSE)

def index_diffs(path, diffs):
    linenums = []
    re.sub(r'\n', lambda m: linenums.append(m.start()), diffs)
    index = []
    for m in interesting_changes_re.finditer(diffs):
        line = m.group(m.lastindex)
        if line.startswith(('+"Project-Id-Version:', '+"PO-Revision-Date:')):
            continue
        pos = m.start(m.lastindex)
        index.append((bisect_left(linenums, pos) + 1, line))
    return index

def write_index_for(path):
    with open(path, 'rb') as f:
        diffs = str(f.read(), 'utf-8')
    changes = index_diffs(path, diffs)
    if changes:
        index = path + '.index'
        with open(index, 'wb') as idx:
            for n, line in changes:
                print(("%s:%s: %s" % (path, n, line)).encode('utf-8'),
                      file=idx)
        print("%s: %d changes indexed in %s" % (path, len(changes), index))
    else:
        print("%s: no interesting changes" % path)

if __name__ == '__main__':
    import sys
    for path in sys.argv[1:]:
        write_index_for(path)
