#!/usr/bin/python
# encoding: utf-8
#
# Copyright 2009 Greg Neagle.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#      http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
makecatalogs

Created by Greg Neagle on 2009-03-30.

Recursively scans a directory, looking for installer item info files.  Builds a repo catalog from these files.

TO-DOs:
Maybe generate a checksum so we can verify the installer item is the right one
"""

import sys
import os
import optparse
import plistlib
import subprocess

def validPlist(path):
    cmd = ['/usr/bin/plutil', '-lint', '-s' , path]
    p = subprocess.Popen(cmd, shell=False, bufsize=1, stdin=subprocess.PIPE, 
                         stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (out, err) = p.communicate()
    if p.returncode == 0:
        return True
    else:
        return False
        
def makeCatalogs(repopath):
    pkgsinfopath = os.path.join(repopath, 'pkgsinfo')
    if not os.path.exists(pkgsinfopath):
        print >>sys.stderr, "pkgsinfo path %s doesn't exist!" % pkgsinfopath
        exit(-1)
    
    catalogs = {}
    catalogs['all'] = []    
    for dirpath, dirnames, filenames in os.walk(pkgsinfopath):
        subdir = dirpath[len(pkgsinfopath):]
        for name in filenames:
            if not name.startswith("._") and name != ".DS_Store":
                filepath = os.path.join(dirpath,name)
                if validPlist(filepath):
                    #if it's a valid plist, assume it's a pkginfo file
                    pkginfo = plistlib.readPlist(filepath)
                    #simple sanity checking
                    if 'installer_item_location' in pkginfo:
                        installeritempath = os.path.join(repopath, "pkgs", pkginfo['installer_item_location'])
                        if os.path.exists(installeritempath):
                            catalogs['all'].append(pkginfo)
                            for catalogname in pkginfo.get("catalogs",[]):
                                if not catalogname in catalogs:
                                    catalogs[catalogname] = []
                                catalogs[catalogname].append(pkginfo)
                                print "Adding %s to %s..." % (filepath[len(pkgsinfopath)+1:], catalogname)
                        else:
                            print >>sys.stderr, "WARNING: Info file %s refers to missing installer item: %s" % (filepath[len(pkgsinfopath)+1:], pkginfo['installer_item_location'])
                else:
                    print >>sys.stderr, "WARNING: file %s is not a valid plist" % filepath
                
    # clear out old catalogs
    path = os.path.join(repopath, "catalogs")
    for item in os.listdir(path):
        itempath = os.path.join(path,item)
        if os.path.isfile(itempath):
            os.remove(itempath)
    
    # write the new catalogs
    for key in catalogs.keys():
        catalogpath = os.path.join(repopath, "catalogs", key)
        plistlib.writePlist(catalogs[key], catalogpath)
        

def main():
    usage = "usage: %prog [options] /path/to/repo_root"
    p = optparse.OptionParser(usage=usage)
    options, arguments = p.parse_args()
    if len(arguments) == 0:
        print >>sys.stderr, "Need to specify a path to the repo root!"
        exit(-1)
        
    repopath = arguments[0].rstrip("/")
    if not os.path.exists(repopath):
        print >>sys.stderr, "Repo root path %s doesn't exist!" % repopath
        exit(-1)
            
    makeCatalogs(repopath)

if __name__ == '__main__':
    main()

