git-svn-id: http://svn.sabayonlinux.org/projects/entropy/trunk@196 cd1c1023-2f26-0410-ae45-c471fc1f0318
443 lines
15 KiB
Python
443 lines
15 KiB
Python
#!/usr/bin/python
|
|
'''
|
|
# DESCRIPTION:
|
|
# generic tools for reagent application
|
|
|
|
Copyright (C) 2007 Fabio Erculiani
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
'''
|
|
|
|
# Never do "import portage" here, please use entropyTools binding
|
|
|
|
from entropyConstants import *
|
|
from entropyTools import *
|
|
import commands
|
|
import re
|
|
import sys
|
|
|
|
# Create the manifest file inside the directory provided by
|
|
# 'path' and hash all the *.etpConst['extension'] files
|
|
def createDigest(path):
|
|
if path.endswith(etpConst['extension']):
|
|
# remove file name and keep the rest of the path
|
|
_path = path.split("/")[:len(path.split("/"))-1]
|
|
path = ""
|
|
for i in _path:
|
|
if (i):
|
|
path += "/"+i
|
|
if (not os.path.isdir(path)):
|
|
print_error(path+" does not exist")
|
|
sys.exit(102)
|
|
digestContent = os.listdir(path)
|
|
# only .etp files
|
|
_digestContent = digestContent
|
|
digestContent = []
|
|
for i in _digestContent:
|
|
if i.endswith(etpConst['extension']):
|
|
digestContent.append(i)
|
|
if (not digestContent[0].endswith(etpConst['extension'])):
|
|
print_error(path+" does not contain "+etpConst['extension']+" files")
|
|
sys.exit(103)
|
|
print_info(green(" * ")+red("Digesting files in ")+path)
|
|
digestOut = []
|
|
for i in digestContent:
|
|
digestOut.append("MD5 "+md5sum(path+"/"+i)+" "+i+"\n")
|
|
f = open(path+"/"+etpConst['digestfile'],"w")
|
|
f.writelines(digestOut)
|
|
f.flush()
|
|
f.close()
|
|
|
|
# Returns:
|
|
# True = if it has generated a new .etp file
|
|
# False = if not
|
|
def generator(package):
|
|
|
|
# check if the package provided is valid
|
|
validFile = False
|
|
if os.path.isfile(package) and package.endswith(".tbz2"):
|
|
validFile = True
|
|
if (not validFile):
|
|
print_error("no valid .tbz2 file specified")
|
|
sys.exit(4)
|
|
|
|
packagename = package.split("/")[len(package.split("/"))-1]
|
|
|
|
print_info(yellow(" * ")+red("Processing: ")+bold(packagename)+red(", please wait..."))
|
|
etpData = extractPkgData(package)
|
|
|
|
# look where I can store the file and return its path
|
|
etpOutput, etpOutfilePath = allocateFile(etpData)
|
|
|
|
rc = False
|
|
|
|
if etpOutfilePath is not None:
|
|
print_info(green(" * ")+red("Writing Entropy Specifications file: ")+etpOutfilePath)
|
|
f = open(etpOutfilePath,"w")
|
|
f.writelines(etpOutput)
|
|
f.flush()
|
|
f.close()
|
|
# digesting directory
|
|
createDigest(etpOutfilePath)
|
|
rc = True
|
|
else:
|
|
print_info(green(" * ")+red("Not generating a new Entropy Specifications file, not needed for ")+bold(packagename))
|
|
# clean garbage
|
|
os.system("rm -rf "+etpConst['packagestmpdir']+"/"+etpData['name']+"-"+etpData['version'])
|
|
|
|
return rc
|
|
|
|
# Enzyme tool called, we need to parse the Store directory and call generator()
|
|
def enzyme():
|
|
|
|
# do some magic trans...
|
|
etpConst['packagesstoredir'] = translateArchFromUname(etpConst['packagesstoredir'])
|
|
etpConst['packagessuploaddir'] = translateArchFromUname(etpConst['packagessuploaddir'])
|
|
|
|
tbz2files = os.listdir(etpConst['packagesstoredir'])
|
|
totalCounter = 0
|
|
# counting the number of files
|
|
for i in tbz2files:
|
|
totalCounter += 1
|
|
|
|
if (totalCounter == 0):
|
|
print_info(yellow(" * ")+red("Nothing to do, check later."))
|
|
# then exit gracefully
|
|
sys.exit(0)
|
|
|
|
counter = 0
|
|
etpCreated = 0
|
|
etpNotCreated = 0
|
|
for tbz2 in tbz2files:
|
|
counter += 1
|
|
tbz2name = tbz2.split("/")[len(tbz2.split("/"))-1]
|
|
print_info(" ("+str(counter)+"/"+str(totalCounter)+") Processing "+tbz2name)
|
|
tbz2path = etpConst['packagesstoredir']+"/"+tbz2
|
|
rc = generator(tbz2path)
|
|
if (rc):
|
|
etpCreated += 1
|
|
os.system("mv "+tbz2path+" "+etpConst['packagessuploaddir']+"/ -f")
|
|
else:
|
|
etpNotCreated += 1
|
|
os.system("rm -rf "+tbz2path)
|
|
|
|
print_info(green(" * ")+red("Statistics: ")+blue("etp created: ")+bold(str(etpCreated))+yellow(" - ")+darkblue("etp discarded: ")+bold(str(etpNotCreated)))
|
|
|
|
# This function extracts all the info from a .tbz2 file and returns them
|
|
def extractPkgData(package):
|
|
|
|
# Clean the variables
|
|
for i in etpData:
|
|
etpData[i] = ""
|
|
|
|
print_info(yellow(" * ")+red("Getting package name/version..."),back = True)
|
|
tbz2File = package
|
|
package = package.split(".tbz2")[0]
|
|
package = package.split("-")
|
|
pkgname = ""
|
|
pkglen = len(package)
|
|
if package[pkglen-1].startswith("r"):
|
|
pkgver = package[pkglen-2]+"-"+package[pkglen-1]
|
|
pkglen -= 2
|
|
else:
|
|
pkgver = package[len(package)-1]
|
|
pkglen -= 1
|
|
for i in range(pkglen):
|
|
if i == pkglen-1:
|
|
pkgname += package[i]
|
|
else:
|
|
pkgname += package[i]+"-"
|
|
pkgname = pkgname.split("/")[len(pkgname.split("/"))-1]
|
|
|
|
# Fill Package name and version
|
|
etpData['name'] = pkgname
|
|
etpData['version'] = pkgver
|
|
|
|
print_info(yellow(" * ")+red("Getting package md5..."),back = True)
|
|
# .tbz2 md5
|
|
etpData['digest'] = md5sum(tbz2File)
|
|
|
|
print_info(yellow(" * ")+red("Unpacking package data..."),back = True)
|
|
# unpack file
|
|
tbz2TmpDir = etpConst['packagestmpdir']+"/"+etpData['name']+"-"+etpData['version']+"/"
|
|
unpackTbz2(tbz2File,tbz2TmpDir)
|
|
|
|
print_info(yellow(" * ")+red("Getting package CHOST..."),back = True)
|
|
# Fill chost
|
|
f = open(tbz2TmpDir+dbCHOST,"r")
|
|
etpData['chost'] = f.readline().strip()
|
|
f.close()
|
|
|
|
print_info(yellow(" * ")+red("Getting package location path..."),back = True)
|
|
# local path to the file
|
|
etpData['packagepath'] = translateArch(etpConst['packagesbindir'],etpData['chost'])+"/"+pkgname+"-"+pkgver+".tbz2"
|
|
|
|
print_info(yellow(" * ")+red("Getting package description..."),back = True)
|
|
# Fill description
|
|
try:
|
|
f = open(tbz2TmpDir+dbDESCRIPTION,"r")
|
|
etpData['description'] = f.readline().strip()
|
|
f.close()
|
|
except IOError:
|
|
etpData['description'] = ""
|
|
|
|
print_info(yellow(" * ")+red("Getting package homepage..."),back = True)
|
|
# Fill homepage
|
|
try:
|
|
f = open(tbz2TmpDir+dbHOMEPAGE,"r")
|
|
etpData['homepage'] = f.readline().strip()
|
|
f.close()
|
|
except IOError:
|
|
etpData['homepage'] = ""
|
|
|
|
print_info(yellow(" * ")+red("Getting package download URL..."),back = True)
|
|
# Fill download relative URI
|
|
etpData['download'] = translateArch(etpConst['binaryurirelativepath']+etpData['name']+"-"+etpData['version']+".tbz2",etpData['chost'])
|
|
|
|
print_info(yellow(" * ")+red("Getting package category..."),back = True)
|
|
# Fill category
|
|
f = open(tbz2TmpDir+dbCATEGORY,"r")
|
|
etpData['category'] = f.readline().strip()
|
|
f.close()
|
|
|
|
print_info(yellow(" * ")+red("Getting package CFLAGS..."),back = True)
|
|
# Fill CFLAGS
|
|
try:
|
|
f = open(tbz2TmpDir+dbCFLAGS,"r")
|
|
etpData['cflags'] = f.readline().strip()
|
|
f.close()
|
|
except IOError:
|
|
etpData['cflags'] = ""
|
|
|
|
print_info(yellow(" * ")+red("Getting package CXXFLAGS..."),back = True)
|
|
# Fill CXXFLAGS
|
|
try:
|
|
f = open(tbz2TmpDir+dbCXXFLAGS,"r")
|
|
etpData['cxxflags'] = f.readline().strip()
|
|
f.close()
|
|
except IOError:
|
|
etpData['cxxflags'] = ""
|
|
|
|
print_info(yellow(" * ")+red("Getting package License information..."),back = True)
|
|
# Fill license
|
|
try:
|
|
f = open(tbz2TmpDir+dbLICENSE,"r")
|
|
etpData['license'] = f.readline().strip()
|
|
f.close()
|
|
except IOError:
|
|
etpData['license'] = ""
|
|
|
|
print_info(yellow(" * ")+red("Getting package sources information..."),back = True)
|
|
# Fill sources
|
|
try:
|
|
f = open(tbz2TmpDir+dbSRC_URI,"r")
|
|
tmpSources = f.readline().strip().split()
|
|
f.close()
|
|
for atom in tmpSources:
|
|
if atom.endswith("?"):
|
|
etpData['sources'] += "="+atom[:len(atom)-1]+"|"
|
|
elif (not atom.startswith("(")) and (not atom.startswith(")")):
|
|
etpData['sources'] += atom+" "
|
|
except IOError:
|
|
etpData['sources'] = ""
|
|
|
|
print_info(yellow(" * ")+red("Getting package mirrors list..."),back = True)
|
|
# manage etpData['sources'] to create etpData['mirrorlinks']
|
|
# =mirror://openoffice|link1|link2|link3
|
|
tmpMirrorList = etpData['sources'].split()
|
|
for i in tmpMirrorList:
|
|
if i.startswith("mirror://"):
|
|
# parse what mirror I need
|
|
x = i.split("/")[2]
|
|
mirrorlist = getThirdPartyMirrors(x)
|
|
mirrorURI = "mirror://"+x
|
|
out = "="+mirrorURI+"|"
|
|
for mirror in mirrorlist:
|
|
out += mirror+"|"
|
|
if out.endswith("|"):
|
|
out = out[:len(out)-1]
|
|
etpData['mirrorlinks'] += out+" "
|
|
etpData['mirrorlinks'] = removeSpaceAtTheEnd(etpData['mirrorlinks'])
|
|
|
|
print_info(yellow(" * ")+red("Getting package USE flags..."),back = True)
|
|
# Fill USE
|
|
f = open(tbz2TmpDir+dbUSE,"r")
|
|
tmpUSE = f.readline().strip()
|
|
f.close()
|
|
try:
|
|
f = open(tbz2TmpDir+dbIUSE,"r")
|
|
tmpIUSE = f.readline().strip().split()
|
|
f.close()
|
|
except IOError:
|
|
tmpIUSE = ""
|
|
|
|
for i in tmpIUSE:
|
|
if tmpUSE.find(i) != -1:
|
|
etpData['useflags'] += i+" "
|
|
else:
|
|
etpData['useflags'] += "-"+i+" "
|
|
|
|
# cleanup
|
|
tmpUSE = etpData['useflags'].split()
|
|
tmpUSE = list(set(tmpUSE))
|
|
etpData['useflags'] = ''
|
|
for i in tmpUSE:
|
|
etpData['useflags'] += i+" "
|
|
etpData['useflags'] = removeSpaceAtTheEnd(etpData['useflags'])
|
|
|
|
print_info(yellow(" * ")+red("Getting sorce package supported ARCHs..."),back = True)
|
|
# fill KEYWORDS
|
|
try:
|
|
f = open(tbz2TmpDir+dbKEYWORDS,"r")
|
|
etpData['keywords'] = f.readline().strip()
|
|
f.close()
|
|
except IOError:
|
|
etpData['keywords'] = ""
|
|
|
|
print_info(yellow(" * ")+red("Getting package supported ARCHs..."),back = True)
|
|
# fill ARCHs
|
|
pkgArchs = etpData['keywords']
|
|
for i in ETP_ARCHS:
|
|
if pkgArchs.find(i) != -1 and (pkgArchs.find("-"+i) == -1): # in case we find something like -amd64...
|
|
etpData['binkeywords'] += i+" "
|
|
etpData['binkeywords'] = removeSpaceAtTheEnd(etpData['binkeywords'])
|
|
|
|
# FIXME: do we have to rewrite this and use Portage to query a better dependency list?
|
|
print_info(yellow(" * ")+red("Getting package dependencies..."),back = True)
|
|
# Fill dependencies
|
|
# to fill dependencies we use *DEPEND files
|
|
f = open(tbz2TmpDir+dbDEPEND,"r")
|
|
roughDependencies = f.readline().strip()
|
|
f.close()
|
|
f = open(tbz2TmpDir+dbRDEPEND,"r")
|
|
roughDependencies += " "+f.readline().strip()
|
|
f.close()
|
|
f = open(tbz2TmpDir+dbPDEPEND,"r")
|
|
roughDependencies += " "+f.readline().strip()
|
|
f.close()
|
|
roughDependencies = roughDependencies.split()
|
|
|
|
# variables filled
|
|
# etpData['dependencies'], etpData['conflicts']
|
|
etpData['dependencies'], etpData['conflicts'] = synthetizeRoughDependencies(roughDependencies,etpData['useflags'])
|
|
|
|
# etpData['rdependencies']
|
|
# Now we need to add environmental dependencies
|
|
# Notes (take the example of mplayer that needed a newer libcaca release):
|
|
# - we can use (from /var/db) "NEEDED" file to catch all the needed libraries to run the binary package
|
|
# - we can use (from /var/db) "CONTENTS" to rapidly search the NEEDED files in the file above
|
|
# return all the collected info
|
|
|
|
print_info(yellow(" * ")+red("Getting package runtime dependencies..."),back = True)
|
|
# start collecting needed libraries
|
|
runtimeNeededPackages, runtimeNeededPackagesXT = getPackageRuntimeDependencies(tbz2TmpDir+"/"+dbNEEDED)
|
|
|
|
# now keep only the ones not available in etpData['dependencies']
|
|
for i in runtimeNeededPackages:
|
|
if etpData['dependencies'].find(i) == -1:
|
|
# filter itself
|
|
if (i != etpData['category']+"/"+etpData['name']):
|
|
etpData['rundependencies'] += i+" "
|
|
|
|
for i in runtimeNeededPackagesXT:
|
|
x = dep_getkey(i)
|
|
if etpData['dependencies'].find(x) == -1:
|
|
# filter itself
|
|
if (x != etpData['category']+"/"+etpData['name']):
|
|
etpData['rundependenciesXT'] += i+" "
|
|
|
|
# format properly
|
|
etpData['rundependencies'] = removeSpaceAtTheEnd(etpData['rundependencies'])
|
|
etpData['rundependenciesXT'] = removeSpaceAtTheEnd(etpData['rundependenciesXT'])
|
|
|
|
print_info(yellow(" * ")+red("Getting Reagent API version..."),back = True)
|
|
# write API info
|
|
etpData['etpapi'] = ETP_API
|
|
|
|
print_info(yellow(" * ")+red("Done"),back = True)
|
|
return etpData
|
|
|
|
# This function generates the right path for putting the .etp file
|
|
# and take count of already available ones bumping version only if needed
|
|
def allocateFile(etpData):
|
|
|
|
# this will be the first thing to return
|
|
etpOutput = []
|
|
# append header
|
|
etpOutput.append(ETP_HEADER_TEXT)
|
|
|
|
# order keys
|
|
keys = []
|
|
for i in etpData:
|
|
keys.append(i)
|
|
|
|
sortedKeys = alphaSorter(keys)
|
|
|
|
for i in sortedKeys:
|
|
if (etpData[i]):
|
|
etpOutput.append(i+": "+etpData[i]+"\n")
|
|
|
|
# locate directory structure
|
|
etpOutfileDir = etpConst['packagesdatabasedir']+"/"+etpData['category']+"/"+etpData['name']
|
|
etpOutfileDir = translateArch(etpOutfileDir,etpData['chost'])
|
|
etpOutfileName = etpData['name']+"-"+etpData['version']+"-etp"+ETP_REVISION_CONST+etpConst['extension']
|
|
etpOutfilePath = etpOutfileDir+"/"+etpOutfileName
|
|
|
|
# we've the directory, then create it
|
|
if (not os.path.isdir(etpOutfileDir)):
|
|
try:
|
|
os.makedirs(etpOutfileDir)
|
|
except OSError:
|
|
pass
|
|
# it's a brand new dir
|
|
etpOutfilePath = re.subn(ETP_REVISION_CONST,"1", etpOutfilePath)[0]
|
|
else: # directory already exists, check for already available files
|
|
alreadyAvailableFiles = []
|
|
for i in range(MAX_ETP_REVISION_COUNT+1):
|
|
testfile = re.subn(ETP_REVISION_CONST,str(i), etpOutfilePath)[0]
|
|
if (os.path.isfile(testfile)):
|
|
alreadyAvailableFiles.append(testfile)
|
|
if (alreadyAvailableFiles == []):
|
|
etpOutfilePath = re.subn(ETP_REVISION_CONST,"1", etpOutfilePath)[0]
|
|
else:
|
|
# grab the last one
|
|
possibleOldFile = alreadyAvailableFiles[len(alreadyAvailableFiles)-1]
|
|
# now compares both to see if they're equal or not
|
|
try:
|
|
import md5
|
|
import string
|
|
a = open(possibleOldFile,"r")
|
|
cntA = a.readlines()
|
|
cntB = etpOutput
|
|
cntA = string.join(cntA)
|
|
cntB = string.join(cntB)
|
|
a.close()
|
|
md5A = md5.new()
|
|
md5B = md5.new()
|
|
md5A.update(cntA)
|
|
md5B.update(cntB)
|
|
|
|
if (md5A.digest() == md5B.digest()):
|
|
etpOutfilePath = None
|
|
else:
|
|
# add 1 to: packagename-1.2.3-r1-etpX.etp
|
|
newFileCounter = int(possibleOldFile.split("-")[len(possibleOldFile.split("-"))-1].split(etpConst['extension'])[0].split(etpConst['extension'][1:])[1])
|
|
newFileCounter += 1
|
|
etpOutfilePath = re.subn(ETP_REVISION_CONST,str(newFileCounter), etpOutfilePath)[0]
|
|
except OSError:
|
|
etpOutfilePath = possibleOldFile
|
|
|
|
return etpOutput, etpOutfilePath
|