Welcome to mirror list, hosted at ThFree Co, Russian Federation.

dedupsrc.py « calm - cygwin.com/git/cygwin-apps/calm.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 2c71d52efedfff1cf257ebff7ec8ef479414404c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#!/usr/bin/env python3
#
# Copyright (c) 2017 Jon Turney
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#

#
# Move a given source archive to src/ (assuming it is indentical in x86/ and
# x86_64/) and adjust hints appropriately.
# (XXX: could probably be extended to move to noarch/ if not source, as well)
#

import argparse
import copy
import os
import re
import sys

from . import common_constants
from . import hint
from . import utils

binary_only_hints = ['requires', 'depends', 'obsoletes', 'external-source']

#
#
#


def hint_file_write(fn, hints):
    with open(fn, 'w') as f:
        for k, v in hints.items():
            print("%s: %s" % (k, v), file=f)


#
#
#

def invent_sdesc(path, vr):
    for (dirpath, _subdirs, files) in os.walk(path):
        # debuginfo packages never have a good sdesc
        if 'debuginfo' in dirpath:
            continue

        # but just pick the sdesc from first sub-package which has one ...
        for f in files:
            if re.match('^.*-' + re.escape(vr) + '.hint$', f):
                hints = hint.hint_file_parse(os.path.join(dirpath, f), hint.pvr)
                if 'sdesc' in hints:
                    sdesc = hints['sdesc']

                    # ... which doesn't contain 'Obsoleted'
                    if 'Obsoleted' in sdesc:
                        continue

                    # remove anything inside parentheses at the end of quoted
                    # sdesc
                    sdesc = re.sub(r'"(.*)"', r'\1', sdesc)
                    sdesc = re.sub(r'(\(.*?\))$', '', sdesc)
                    sdesc = sdesc.strip()
                    sdesc = '"' + sdesc + '"'

                    return sdesc

    return None
#
#
#


def dedup(archive, relarea):
    # split path and filename
    (path, filename) = os.path.split(archive)

    # parse tarfile name
    match = re.match(r'^(.+?)-(\d.*)-src\.tar' +
                     common_constants.PACKAGE_COMPRESSIONS_RE + r'$', filename)

    if not match:
        print('tarfile name %s does not meet expectations' % (filename))
        sys.exit(1)

    p = match.group(1)
    vr = match.group(2)
    ext = match.group(3)

    # compute filenames
    to_filename = p + '-src-' + vr + '.tar.' + ext
    hint_filename = p + '-' + vr + '.hint'
    to_hint_filename = p + '-src-' + vr + '.hint'

    # read hints for both arches
    hints = {}
    for arch in ['x86', 'x86_64']:
        hint_pathname = os.path.join(relarea, arch, path, hint_filename)

        if not os.path.exists(hint_pathname):
            print('%s not found' % (hint_pathname))
            return 1

        hints[arch] = hint.hint_file_parse(hint_pathname, hint.pvr)

        # remove hints which only have meaning for binary packages
        #
        # (requires: tends to have libgcc1 more often on x86, so otherwise this
        # would cause spurious differences between hints to be reported)
        for h in binary_only_hints:
            if h in hints[arch]:
                del hints[arch][h]

    if hints['x86'] != hints['x86_64']:
        print('hints for %s-%s differ between arches' % (p, vr))
        return 1

    if ('skip' in hints['x86']) and (len(hints['x86']) == 1):
        print('hints for %s-%s is skip: only' % (p, vr))
        hints['x86']['category'] = ''
        # if hint only contains skip:, try to come up with a plausible sdesc
        sdesc = invent_sdesc(os.path.join(relarea, 'x86', path), vr)
        if sdesc:
            print('suggested sdesc is %s' % (sdesc))
            hints['x86']['sdesc'] = sdesc

    if 'sdesc' not in hints['x86']:
        print('hints for %s-%s has no sdesc:' % (p, vr))
        return 1

    # ensure target directory exists
    utils.makedirs(os.path.join(relarea, 'src', path, p + '-src'))

    # write .hint file for new -src package
    src_hints = copy.copy(hints['x86'])

    if 'source' not in src_hints['sdesc']:
        sdesc = re.sub(r'"(.*)"', r'\1', src_hints['sdesc'])
        sdesc += ' (source code)'
        src_hints['sdesc'] = '"' + sdesc + '"'

    if 'Source' not in src_hints['category']:
        src_hints['category'] = src_hints['category'] + ' Source'

    if 'parse-warnings' in src_hints:
        del src_hints['parse-warnings']

    to_hint_pathname = os.path.join(relarea, 'src', path, p + '-src', to_hint_filename)
    print('writing %s' % (to_hint_pathname))
    hint_file_write(to_hint_pathname, src_hints)

    # move the src files to src/
    for arch in ['x86', 'x86_64']:
        print('%s -> %s' % (os.path.join(relarea, arch, path, filename), os.path.join(relarea, 'src', path, p + '-src', to_filename)))
        os.rename(os.path.join(relarea, arch, path, filename), os.path.join(relarea, 'src', path, p + '-src', to_filename))

    # adjust external-source in .hint for all subpackages
    for arch in ['x86', 'x86_64']:
        for (dirpath, _subdirs, files) in os.walk(os.path.join(relarea, arch, path)):
            subpkg = os.path.basename(dirpath)
            filename = subpkg + '-' + vr + '.hint'
            if filename in files:
                hint_pathname = os.path.join(dirpath, filename)
                hints = hint.hint_file_parse(hint_pathname, hint.pvr)
                if 'parse-warnings' in hints:
                    del hints['parse-warnings']
                if ('skip' in hints):
                    # p was source only, so no package remains
                    print('removing %s' % (hint_pathname))
                    os.remove(hint_pathname)
                elif ('external-source' not in hints) or (hints['external-source'] == p):
                    hints['external-source'] = p + '-src'
                    print('writing %s' % (hint_pathname))
                    hint_file_write(hint_pathname, hints)

    return 0

#
#
#


def main():
    relarea_default = common_constants.FTP

    parser = argparse.ArgumentParser(description='Source package deduplicator')
    parser.add_argument('archive', metavar='ARCHIVE', nargs=1, help="source archive to deduplicate")
    parser.add_argument('--releasearea', action='store', metavar='DIR', help="release directory (default: " + relarea_default + ")", default=relarea_default, dest='rel_area')
    (args) = parser.parse_args()

    return dedup(args.archive[0], args.rel_area)


#
#
#

if __name__ == "__main__":
    sys.exit(main())