source: soft/build_system/build_system/repsys/tags/V1_6_17_1/RepSys/rpmutil.py @ 1

Last change on this file since 1 was 1, checked in by fasma, 13 years ago

Initial Import from Mandriva's soft revision 224062 and package revision 45733

File size: 17.5 KB
Line 
1#!/usr/bin/python
2from RepSys import Error, config, RepSysTree
3from RepSys import mirror
4from RepSys.svn import SVN
5from RepSys.simplerpm import SRPM
6from RepSys.log import specfile_svn2rpm
7from RepSys.util import execcmd
8import rpm
9import tempfile
10import shutil
11import glob
12import sys
13import os
14
15def get_spec(pkgdirurl, targetdir=".", submit=False):
16    svn = SVN(baseurl=pkgdirurl)
17    tmpdir = tempfile.mktemp()
18    try:
19        geturl = "/".join([pkgdirurl, "current", "SPECS"])
20        svn.export("'%s'" % geturl, tmpdir)
21        speclist = glob.glob(os.path.join(tmpdir, "*.spec"))
22        if not speclist:
23            raise Error, "no spec files found"
24        spec = speclist[0]
25        shutil.copy(spec, targetdir)
26    finally:
27        if os.path.isdir(tmpdir):
28            shutil.rmtree(tmpdir)
29
30def rpm_macros_defs(macros):
31    defs = ("--define \"%s %s\"" % macro for macro in macros)
32    args = " ".join(defs)
33    return args
34
35def get_srpm(pkgdirurl,
36             mode = "current",
37             targetdirs = None,
38             version = None,
39             release = None,
40             revision = None,
41             packager = "",
42             revname = 0,
43             svnlog = 0,
44             scripts = [], 
45             submit = False,
46             template = None,
47             macros = [],
48             verbose = 0):
49    svn = SVN(baseurl=pkgdirurl)
50    tmpdir = tempfile.mktemp()
51    topdir = "--define '_topdir %s'" % tmpdir
52    builddir = "--define '_builddir %s/%s'" % (tmpdir, "BUILD")
53    rpmdir = "--define '_rpmdir %s/%s'" % (tmpdir, "RPMS")
54    sourcedir = "--define '_sourcedir %s/%s'" % (tmpdir, "SOURCES")
55    specdir = "--define '_specdir %s/%s'" % (tmpdir, "SPECS")
56    srcrpmdir = "--define '_srcrpmdir %s/%s'" % (tmpdir, "SRPMS")
57    patchdir = "--define '_patchdir %s/%s'" % (tmpdir, "SOURCES")
58    try:
59        if mode == "version":
60            geturl = os.path.join(pkgdirurl, "versions",
61                                  version, release)
62        elif mode == "pristine":
63            geturl = os.path.join(pkgdirurl, "pristine")
64        elif mode == "current" or mode == "revision":
65            geturl = os.path.join(pkgdirurl, "current")
66        else:
67            raise Error, "unsupported get_srpm mode: %s" % mode
68        svn.export(geturl, tmpdir, rev=revision)
69        srpmsdir = os.path.join(tmpdir, "SRPMS")
70        os.mkdir(srpmsdir)
71        specsdir = os.path.join(tmpdir, "SPECS")
72        speclist = glob.glob(os.path.join(specsdir, "*.spec"))
73        if not speclist:
74            raise Error, "no spec files found"
75        spec = speclist[0]
76        if svnlog:
77            submit = not not revision
78            specfile_svn2rpm(pkgdirurl, spec, revision, submit=submit,
79                    template=template, macros=macros)
80        revisionreal = svn.revision(pkgdirurl)
81        for script in scripts:
82            status, output = execcmd(script, tmpdir, spec, str(revision),
83                                     noerror=1)
84            if status != 0:
85                raise Error, "script %s failed" % script
86        if packager:
87            packager = " --define 'packager %s'" % packager
88
89        defs = rpm_macros_defs(macros)
90        execcmd("rpm -bs --nodeps %s %s %s %s %s %s %s %s %s %s" %
91            (topdir, builddir, rpmdir, sourcedir, specdir, 
92             srcrpmdir, patchdir, packager, spec, defs))
93
94        if revision and revisionreal:
95            srpm = glob.glob(os.path.join(srpmsdir, "*.src.rpm"))[0]
96            srpminfo = SRPM(srpm)
97            release = srpminfo.release
98            srpmbase = os.path.basename(srpm)
99            os.rename(srpm, "%s/@%s:%s" % (srpmsdir, revisionreal, srpmbase))
100        srpm = glob.glob(os.path.join(srpmsdir, "*.src.rpm"))[0]
101        if not targetdirs:
102            targetdirs = (".",)
103        targetsrpms = []
104        for targetdir in targetdirs:
105            targetsrpm = os.path.join(os.path.realpath(targetdir), 
106                    os.path.basename(srpm))
107            targetsrpms.append(targetsrpm)
108            if verbose:
109                sys.stderr.write("Wrote: %s\n" %  targetsrpm)
110            execcmd("cp -f", srpm, targetdir)
111        os.unlink(srpm)
112        return targetsrpms
113    finally:
114        if os.path.isdir(tmpdir):
115            shutil.rmtree(tmpdir)
116
117def patch_spec(pkgdirurl, patchfile, log=""):
118    svn = SVN(baseurl=pkgdirurl)
119    tmpdir = tempfile.mktemp()
120    try:
121        geturl = "/".join([pkgdirurl, "current", "SPECS"])
122        svn.checkout(geturl, tmpdir)
123        speclist = glob.glob(os.path.join(tmpdir, "*.spec"))
124        if not speclist:
125            raise Error, "no spec files found"
126        spec = speclist[0]
127        status, output = execcmd("patch", spec, patchfile)
128        if status != 0:
129            raise Error, "can't apply patch:\n%s\n" % output
130        else:
131            svn.commit(tmpdir, log="")
132    finally:
133        if os.path.isdir(tmpdir):
134            shutil.rmtree(tmpdir)
135
136def put_srpm(pkgdirurl, srpmfile, appendname=0, log=""):
137    srpm = SRPM(srpmfile)
138    if appendname:
139        pkgdirurl = "/".join([pkgdirurl, srpm.name])
140    svn = SVN(baseurl=pkgdirurl)
141    tmpdir = tempfile.mktemp()
142    try:
143        if srpm.epoch:
144            version = "%s:%s" % (srpm.epoch, srpm.version)
145        else:
146            version = srpm.version
147        versionurl = "/".join([pkgdirurl, "releases", version])
148        releaseurl = "/".join([versionurl, srpm.release])
149        ret = svn.mkdir(pkgdirurl, noerror=1, log="Created package directory")
150        if ret:
151            svn.checkout(pkgdirurl, tmpdir)
152            svn.mkdir(os.path.join(tmpdir, "releases"))
153            svn.mkdir(os.path.join(tmpdir, "releases", version))
154            svn.mkdir(os.path.join(tmpdir, "current"))
155            svn.mkdir(os.path.join(tmpdir, "current", "SPECS"))
156            svn.mkdir(os.path.join(tmpdir, "current", "SOURCES"))
157            #svn.commit(tmpdir,log="Created package structure.")
158            version_exists = 1
159            currentdir = os.path.join(tmpdir, "current")
160        else:
161            if svn.ls(releaseurl, noerror=1):
162                raise Error, "release already exists"
163            svn.checkout("/".join([pkgdirurl, "current"]), tmpdir)
164            svn.mkdir(versionurl, noerror=1,
165                      log="Created directory for version %s." % version)
166            currentdir = tmpdir
167         
168        specsdir = os.path.join(currentdir, "SPECS")
169        sourcesdir = os.path.join(currentdir, "SOURCES")
170
171        unpackdir = tempfile.mktemp()
172        os.mkdir(unpackdir)
173        try:
174            srpm.unpack(unpackdir)
175
176            uspecsdir = os.path.join(unpackdir, "SPECS")
177            usourcesdir = os.path.join(unpackdir, "SOURCES")
178           
179            uspecsentries = os.listdir(uspecsdir)
180            usourcesentries = os.listdir(usourcesdir)
181            specsentries = os.listdir(specsdir)
182            sourcesentries = os.listdir(sourcesdir)
183
184            # Remove old entries
185            for entry in [x for x in specsentries
186                             if x not in uspecsentries]:
187                if entry == ".svn":
188                    continue
189                entrypath = os.path.join(specsdir, entry)
190                os.unlink(entrypath)
191                svn.remove(entrypath)
192            for entry in [x for x in sourcesentries
193                             if x not in usourcesentries]:
194                if entry == ".svn":
195                    continue
196                entrypath = os.path.join(sourcesdir, entry)
197                os.unlink(entrypath)
198                svn.remove(entrypath)
199
200            # Copy all files
201            execcmd("cp -rf", uspecsdir, currentdir)
202            execcmd("cp -rf", usourcesdir, currentdir)
203           
204            # Add new entries
205            for entry in [x for x in uspecsentries
206                             if x not in specsentries]:
207                entrypath = os.path.join(specsdir, entry)
208                svn.add(entrypath)
209            for entry in [x for x in usourcesentries
210                             if x not in sourcesentries]:
211                entrypath = os.path.join(sourcesdir, entry)
212                svn.add(entrypath)
213        finally:
214            if os.path.isdir(unpackdir):
215                shutil.rmtree(unpackdir)
216
217        svn.commit(tmpdir, log=log)
218    finally:
219        if os.path.isdir(tmpdir):
220            shutil.rmtree(tmpdir)
221
222    # Do revision and pristine tag copies
223    pristineurl = os.path.join(pkgdirurl, "pristine")
224    svn.remove(pristineurl, noerror=1,
225               log="Removing previous pristine/ directory.")
226    currenturl = os.path.join(pkgdirurl, "current")
227    svn.copy(currenturl, pristineurl,
228             log="Copying release %s-%s to pristine/ directory." %
229                 (version, srpm.release))
230    svn.copy(currenturl, releaseurl,
231             log="Copying release %s-%s to releases/ directory." %
232                 (version, srpm.release))
233
234def create_package(pkgdirurl, log="", verbose=0):
235    svn = SVN(baseurl=pkgdirurl)
236    tmpdir = tempfile.mktemp()
237    try:
238        basename = RepSysTree.pkgname(pkgdirurl)
239        if verbose:
240            print "Creating package directory...",
241        sys.stdout.flush()
242        ret = svn.mkdir(pkgdirurl,
243                        log="Created package directory for '%s'." % basename)
244        if verbose:
245            print "done"
246            print "Checking it out...",
247        svn.checkout(pkgdirurl, tmpdir)
248        if verbose:
249            print "done"
250            print "Creating package structure...",
251        svn.mkdir(os.path.join(tmpdir, "current"))
252        svn.mkdir(os.path.join(tmpdir, "current", "SPECS"))
253        svn.mkdir(os.path.join(tmpdir, "current", "SOURCES"))
254        if verbose:
255            print "done"
256            print "Committing...",
257        svn.commit(tmpdir,
258                   log="Created package structure for '%s'." % basename)
259        print "done"
260    finally:
261        if os.path.isdir(tmpdir):
262            shutil.rmtree(tmpdir)
263
264
265def create_markrelease_log(version, release, revision):
266    log = """%%repsys markrelease
267version: %s
268release: %s
269revision: %s
270
271%s""" % (version, release, revision, 
272        ("Copying %s-%s to releases/ directory." % (version, release)))
273    return log
274
275def mark_release(pkgdirurl, version, release, revision):
276    svn = SVN(baseurl=pkgdirurl)
277    releasesurl = "/".join([pkgdirurl, "releases"])
278    versionurl = "/".join([releasesurl, version])
279    releaseurl = "/".join([versionurl, release])
280    if svn.ls(releaseurl, noerror=1):
281        raise Error, "release already exists"
282    svn.mkdir(releasesurl, noerror=1,
283              log="Created releases directory.")
284    svn.mkdir(versionurl, noerror=1,
285              log="Created directory for version %s." % version)
286    pristineurl = os.path.join(pkgdirurl, "pristine")
287    svn.remove(pristineurl, noerror=1,
288               log="Removing previous pristine/ directory.")
289    currenturl = os.path.join(pkgdirurl, "current")
290    svn.copy(currenturl, pristineurl,
291             log="Copying release %s-%s to pristine/ directory." %
292                 (version, release))
293    markreleaselog = create_markrelease_log(version, release, revision)
294    svn.copy(currenturl, releaseurl, rev=revision,
295             log=markreleaselog)
296
297def check_changed(pkgdirurl, all=0, show=0, verbose=0):
298    svn = SVN(baseurl=pkgdirurl)
299    if all:
300        baseurl = pkgdirurl
301        packages = []
302        if verbose:
303            print "Getting list of packages...",
304            sys.stdout.flush()
305        packages = [x[:-1] for x in svn.ls(baseurl)]
306        if verbose:
307            print "done"
308        if not packages:
309            raise Error, "couldn't get list of packages"
310    else:
311        baseurl, basename = os.path.split(pkgdirurl)
312        packages = [basename]
313    clean = []
314    changed = []
315    nopristine = []
316    nocurrent = []
317    for package in packages:
318        pkgdirurl = os.path.join(baseurl, package)
319        current = os.path.join(pkgdirurl, "current")
320        pristine = os.path.join(pkgdirurl, "pristine")
321        if verbose:
322            print "Checking package %s..." % package,
323            sys.stdout.flush()
324        if not svn.ls(current, noerror=1):
325            if verbose:
326                print "NO CURRENT"
327            nocurrent.append(package)
328        elif not svn.ls(pristine, noerror=1):
329            if verbose:
330                print "NO PRISTINE"
331            nopristine.append(package)
332        else:
333            diff = svn.diff(pristine, current)
334            if diff:
335                changed.append(package)
336                if verbose:
337                    print "CHANGED"
338                if show:
339                    print diff
340            else:
341                if verbose:
342                    print "clean"
343                clean.append(package)
344    if verbose:
345        if not packages:
346            print "No packages found!"
347        elif all:
348            print "Total clean packages: %s" % len(clean)
349            print "Total CHANGED packages: %d" % len(changed)
350            print "Total NO CURRENT packages: %s" % len(nocurrent)
351            print "Total NO PRISTINE packages: %s" % len(nopristine)
352    return {"clean": clean,
353            "changed": changed,
354            "nocurrent": nocurrent,
355            "nopristine": nopristine}
356
357def checkout(pkgdirurl, path=None, revision=None):
358    svn = SVN(baseurl=pkgdirurl)
359    current = os.path.join(pkgdirurl, "current")
360    if path is None:
361        _, path = os.path.split(pkgdirurl)
362    if mirror.enabled():
363        current = mirror.checkout_url(current)
364        print "checking out from mirror", current
365    svn.checkout(current, path, rev=revision, show=1)
366
367def sync(dryrun=False):
368    svn = SVN(noauth=True)
369    cwd = os.getcwd()
370    dirname = os.path.basename(cwd)
371    if dirname == "SPECS" or dirname == "SOURCES":
372        topdir = os.pardir
373    else:
374        topdir = ""
375    # run svn info because svn st does not complain when topdir is not an
376    # working copy
377    svn.info(topdir or ".")
378    specsdir = os.path.join(topdir, "SPECS/")
379    sourcesdir = os.path.join(topdir, "SOURCES/")
380    for path in (specsdir, sourcesdir):
381        if not os.path.isdir(path):
382            raise Error, "%s directory not found" % path
383    specs = glob.glob(os.path.join(specsdir, "*.spec"))
384    if not specs:
385        raise Error, "no .spec files found in %s" % specsdir
386    specpath = specs[0] # FIXME better way?
387    try:
388        spec = rpm.TransactionSet().parseSpec(specpath)
389    except rpm.error, e:
390        raise Error, "could not load spec file: %s" % e
391    sources = [os.path.basename(name)
392            for name, no, flags in spec.sources()]
393    sourcesst = dict((os.path.basename(path), st)
394            for st, path in svn.status(sourcesdir, noignore=True))
395    toadd = []
396    for source in sources:
397        sourcepath = os.path.join(sourcesdir, source)
398        if sourcesst.get(source):
399            if os.path.isfile(sourcepath):
400                toadd.append(sourcepath)
401            else:
402                sys.stderr.write("warning: %s not found\n" % sourcepath)
403    # rm entries not found in sources and still in svn
404    found = os.listdir(sourcesdir)
405    toremove = []
406    for entry in found:
407        if entry == ".svn":
408            continue
409        status = sourcesst.get(entry)
410        if status is None and entry not in sources:
411            path = os.path.join(sourcesdir, entry)
412            toremove.append(path)
413    for path in toremove:
414        print "D\t%s" % path
415        if not dryrun:
416            svn.remove(path, local=True)
417    for path in toadd:
418        print "A\t%s" % path
419        if not dryrun:
420            svn.add(path, local=True)
421
422def commit(target=".", message=None):
423    svn = SVN(noauth=True)
424    info = svn.info2(target)
425    url = info.get("URL")
426    if url is None:
427        raise Error, "working copy URL not provided by svn info"
428    if mirror.enabled():
429        newurl = mirror.switchto_parent(svn, url, target)
430        print "relocated to", newurl
431    try:
432        # we can't use the svn object here because pexpect hides VISUAL
433        mopt = ""
434        if message is not None:
435            mopt = "-m \"%s\"" % message
436        os.system("svn ci %s %s" % (mopt, target))
437    finally:
438        if mirror.enabled():
439            mirror.switchto_mirror(svn, newurl, target)
440            print "relocated back to", url
441
442def get_submit_info(path):
443    path = os.path.abspath(path)
444
445    # First, look for SPECS and SOURCES directories.
446    found = False
447    while path != "/":
448        if os.path.isdir(path):
449            specsdir = os.path.join(path, "SPECS")
450            sourcesdir = os.path.join(path, "SOURCES")
451            if os.path.isdir(specsdir) and os.path.isdir(sourcesdir):
452                found = True
453                break
454        path = os.path.dirname(path)
455    if not found:
456        raise Error, "SPECS and/or SOURCES directories not found"
457
458    # Then, check if this is really a subversion directory.
459    if not os.path.isdir(os.path.join(path, ".svn")):
460        raise Error, "subversion directory not found"
461   
462    svn = SVN(baseurl=pkgdirurl)
463
464
465    # Now, extract the package name.
466    for line in svn.info(path):
467        if line.startswith("URL: "):
468            url = line.split()[1]
469            toks = url.split("/")
470            if len(toks) < 2 or toks[-1] != "current":
471                raise Error, "unexpected URL received from 'svn info'"
472            name = toks[-2]
473            break
474    else:
475        raise Error, "URL tag not found in 'svn info' output"
476
477    # Finally, guess revision.
478    max = -1
479    files = []
480    files.extend(glob.glob("%s/*" % specsdir))
481    files.extend(glob.glob("%s/*" % sourcesdir))
482    for line in svn.info(" ".join(files)):
483        if line.startswith("Revision: "):
484            rev = int(line.split()[1])
485            if rev > max:
486                max = rev
487    if max == -1:
488        raise Error, "revision tag not found in 'svn info' output"
489   
490    return name, max
491
492# vim:et:ts=4:sw=4
Note: See TracBrowser for help on using the repository browser.