* File: add support for those remote signatures
* implement signatures for index
This commit is contained in:
+12
-5
@@ -301,7 +301,7 @@ def index(dirs, output = 'pisi-index.xml', skip_sources=False):
|
|||||||
repo_dir = str(repo_dir)
|
repo_dir = str(repo_dir)
|
||||||
ctx.ui.info(_('* Building index of PISI files under %s') % repo_dir)
|
ctx.ui.info(_('* Building index of PISI files under %s') % repo_dir)
|
||||||
index.index(repo_dir, skip_sources)
|
index.index(repo_dir, skip_sources)
|
||||||
index.write(output, sha1sum=True, compress=File.xmill)
|
index.write(output, sha1sum=True, compress=File.xmill, sign=File.detached)
|
||||||
ctx.ui.info(_('* Index file written'))
|
ctx.ui.info(_('* Index file written'))
|
||||||
|
|
||||||
def add_repo(name, indexuri):
|
def add_repo(name, indexuri):
|
||||||
@@ -321,15 +321,22 @@ def update_repo(repo, force=False):
|
|||||||
ctx.ui.info(_('* Updating repository: %s') % repo)
|
ctx.ui.info(_('* Updating repository: %s') % repo)
|
||||||
index = Index()
|
index = Index()
|
||||||
if ctx.repodb.has_repo(repo):
|
if ctx.repodb.has_repo(repo):
|
||||||
|
repouri = ctx.repodb.get_repo(repo).indexuri.get_uri()
|
||||||
try:
|
try:
|
||||||
index.read_uri(ctx.repodb.get_repo(repo).indexuri.get_uri(), repo)
|
index.read_uri(repouri, repo)
|
||||||
ctx.txn_proc(lambda txn : index.update_db(repo, txn=txn))
|
|
||||||
ctx.ui.info(_('* Package database updated.'))
|
|
||||||
except pisi.file.AlreadyHaveException, e:
|
except pisi.file.AlreadyHaveException, e:
|
||||||
ctx.ui.info(_('No updates available for repository %s.' % repo))
|
ctx.ui.info(_('No updates available for repository %s.' % repo))
|
||||||
if force:
|
if force:
|
||||||
ctx.ui.info(_('Updating database at any rate as requested'))
|
ctx.ui.info(_('Updating database at any rate as requested'))
|
||||||
raise Error(_('OPTION NOT IMPLEMENTED YET'))
|
index.read_uri(repouri, repo, force = force)
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
index.check_signature(repouri, repo)
|
||||||
|
except pisi.file.NoSignatureFound, e:
|
||||||
|
ctx.ui.warning(e)
|
||||||
|
ctx.txn_proc(lambda txn : index.update_db(repo, txn=txn))
|
||||||
|
ctx.ui.info(_('* Package database updated.'))
|
||||||
else:
|
else:
|
||||||
raise Error(_('No repository named %s found.') % repo)
|
raise Error(_('No repository named %s found.') % repo)
|
||||||
|
|
||||||
|
|||||||
@@ -73,12 +73,14 @@ class CLI(UI):
|
|||||||
self.output( unicode(msg) + msgend, verbose=verbose)
|
self.output( unicode(msg) + msgend, verbose=verbose)
|
||||||
|
|
||||||
def warning(self, msg, verbose = False):
|
def warning(self, msg, verbose = False):
|
||||||
|
msg = unicode(msg)
|
||||||
if ctx.get_option('no_color'):
|
if ctx.get_option('no_color'):
|
||||||
self.output(_('Warning: ') + msg + '\n', err=True, verbose=verbose)
|
self.output(_('Warning: ') + msg + '\n', err=True, verbose=verbose)
|
||||||
else:
|
else:
|
||||||
self.output(colorize(msg + '\n', 'purple'), err=True, verbose=verbose)
|
self.output(colorize(msg + '\n', 'purple'), err=True, verbose=verbose)
|
||||||
|
|
||||||
def error(self, msg):
|
def error(self, msg):
|
||||||
|
msg = unicode(msg)
|
||||||
if ctx.get_option('no_color'):
|
if ctx.get_option('no_color'):
|
||||||
self.output(_('Error: ') + msg + '\n', err=True)
|
self.output(_('Error: ') + msg + '\n', err=True)
|
||||||
else:
|
else:
|
||||||
@@ -86,6 +88,7 @@ class CLI(UI):
|
|||||||
|
|
||||||
def action(self, msg, verbose = False):
|
def action(self, msg, verbose = False):
|
||||||
#TODO: this seems quite redundant?
|
#TODO: this seems quite redundant?
|
||||||
|
msg = unicode(msg)
|
||||||
self.output(colorize(msg + '\n', 'green'))
|
self.output(colorize(msg + '\n', 'green'))
|
||||||
|
|
||||||
def choose(self, msg, opts):
|
def choose(self, msg, opts):
|
||||||
@@ -102,6 +105,7 @@ class CLI(UI):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def confirm(self, msg):
|
def confirm(self, msg):
|
||||||
|
msg = unicode(msg)
|
||||||
if ctx.config.options and ctx.config.options.yes_all:
|
if ctx.config.options and ctx.config.options.yes_all:
|
||||||
return True
|
return True
|
||||||
while True:
|
while True:
|
||||||
@@ -124,6 +128,7 @@ class CLI(UI):
|
|||||||
|
|
||||||
def status(self, msg = None):
|
def status(self, msg = None):
|
||||||
if msg:
|
if msg:
|
||||||
|
msg = unicode(msg)
|
||||||
self.output(colorize(msg + '\n', 'purple'))
|
self.output(colorize(msg + '\n', 'purple'))
|
||||||
util.xterm_title(msg)
|
util.xterm_title(msg)
|
||||||
|
|
||||||
|
|||||||
+37
-6
@@ -18,7 +18,7 @@ we are just encapsulating a common pattern in our program, nothing big.
|
|||||||
like all pisi classes, it has been programmed in a non-restricting way
|
like all pisi classes, it has been programmed in a non-restricting way
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os.path
|
import os, os.path
|
||||||
import types
|
import types
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
@@ -37,14 +37,26 @@ class AlreadyHaveException(pisi.Exception):
|
|||||||
self.url = url
|
self.url = url
|
||||||
self.localfile = localfile
|
self.localfile = localfile
|
||||||
|
|
||||||
|
class NoSignatureFound(pisi.Exception):
|
||||||
|
def __init__(self, url):
|
||||||
|
pisi.Exception.__init__(self, "No signature found for %s" % url)
|
||||||
|
self.url = url
|
||||||
|
|
||||||
class Error(pisi.Error):
|
class Error(pisi.Error):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class InvalidSignature(pisi.Error):
|
||||||
|
def __init__(self, url):
|
||||||
|
pisi.Exception.__init__(self, " invalid for %s" % url)
|
||||||
|
self.url = url
|
||||||
|
|
||||||
class File:
|
class File:
|
||||||
|
|
||||||
(read, write) = range(2) # modes
|
(read, write) = range(2) # modes
|
||||||
(xmill, sevenzip) = range(2) # compress enums
|
(xmill, sevenzip) = range(2) # compress enums
|
||||||
|
|
||||||
|
(detached, whatelse) = range(2)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def make_uri(uri):
|
def make_uri(uri):
|
||||||
"handle URI arg"
|
"handle URI arg"
|
||||||
@@ -70,6 +82,7 @@ class File:
|
|||||||
sha1sum = False, compress = None, sign = None):
|
sha1sum = False, compress = None, sign = None):
|
||||||
|
|
||||||
assert type(uri == URI)
|
assert type(uri == URI)
|
||||||
|
|
||||||
if sha1sum:
|
if sha1sum:
|
||||||
sha1filename = File.download(URI(uri.get_uri() + '.sha1sum'), transfer_dir)
|
sha1filename = File.download(URI(uri.get_uri() + '.sha1sum'), transfer_dir)
|
||||||
sha1f = file(sha1filename)
|
sha1f = file(sha1filename)
|
||||||
@@ -106,8 +119,13 @@ class File:
|
|||||||
def __init__(self, uri, mode, transfer_dir = "/tmp",
|
def __init__(self, uri, mode, transfer_dir = "/tmp",
|
||||||
sha1sum = False, compress = None, sign = None):
|
sha1sum = False, compress = None, sign = None):
|
||||||
"it is pointless to open a file without a URI and a mode"
|
"it is pointless to open a file without a URI and a mode"
|
||||||
|
|
||||||
|
self.transfer_dir = transfer_dir
|
||||||
self.sha1sum = sha1sum
|
self.sha1sum = sha1sum
|
||||||
self.compress = compress
|
self.compress = compress
|
||||||
|
self.sign = sign
|
||||||
|
|
||||||
|
|
||||||
uri = File.make_uri(uri)
|
uri = File.make_uri(uri)
|
||||||
if mode==File.read or mode==File.write:
|
if mode==File.read or mode==File.write:
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
@@ -137,17 +155,30 @@ class File:
|
|||||||
def close(self, delete_transfer = False):
|
def close(self, delete_transfer = False):
|
||||||
"this method must be called at the end of operation"
|
"this method must be called at the end of operation"
|
||||||
self.__file__.close()
|
self.__file__.close()
|
||||||
if self.compress == File.xmill:
|
|
||||||
pisi.util.run_batch('xcmill -9 -f ' + self.localfile)
|
|
||||||
self.localfile = self.localfile[:-4] + '.xmi'
|
|
||||||
elif self.compress == File.sevenzip:
|
|
||||||
raise Error(_("sevenzip compression not supported yet"))
|
|
||||||
if self.mode == File.write:
|
if self.mode == File.write:
|
||||||
|
if self.compress == File.xmill:
|
||||||
|
pisi.util.run_batch('xcmill -9 -f ' + self.localfile)
|
||||||
|
self.localfile = self.localfile[:-4] + '.xmi'
|
||||||
|
elif self.compress == File.sevenzip:
|
||||||
|
raise Error(_("sevenzip compression not supported yet"))
|
||||||
if self.sha1sum:
|
if self.sha1sum:
|
||||||
sha1 = pisi.util.sha1_file(self.localfile)
|
sha1 = pisi.util.sha1_file(self.localfile)
|
||||||
cs = file(self.localfile + '.sha1sum', 'w')
|
cs = file(self.localfile + '.sha1sum', 'w')
|
||||||
cs.write(sha1)
|
cs.write(sha1)
|
||||||
cs.close()
|
cs.close()
|
||||||
|
if self.sign==File.detached:
|
||||||
|
pisi.util.run_batch('gpg --detach-sig ' + self.localfile)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def check_signature(uri, transfer_dir, sign=detached):
|
||||||
|
if sign==File.detached:
|
||||||
|
try:
|
||||||
|
sigfilename = File.download(URI(uri + '.sig'), transfer_dir)
|
||||||
|
except:
|
||||||
|
raise NoSignatureFound(uri)
|
||||||
|
if os.system('gpg --verify ' + sigfilename) != 0:
|
||||||
|
raise InvalidSignature(uri)
|
||||||
|
# everything is all right here
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
self.__file__.flush()
|
self.__file__.flush()
|
||||||
|
|||||||
+8
-2
@@ -50,10 +50,16 @@ class Index(XmlFile):
|
|||||||
t_Packages = [ [metadata.Package], autoxml.optional, "Package"]
|
t_Packages = [ [metadata.Package], autoxml.optional, "Package"]
|
||||||
t_Components = [ [component.Component], autoxml.optional, "Component"]
|
t_Components = [ [component.Component], autoxml.optional, "Component"]
|
||||||
|
|
||||||
def read_uri(self, filename, repo = None):
|
# read index for a given repo, force means download even if remote not updated
|
||||||
|
def read_uri(self, filename, repo = None, force = False):
|
||||||
"""Read PSPEC file"""
|
"""Read PSPEC file"""
|
||||||
tmpdir = os.path.join(ctx.config.index_dir(), repo)
|
tmpdir = os.path.join(ctx.config.index_dir(), repo)
|
||||||
self.read(filename, tmpDir=tmpdir, sha1sum=True, compress=File.xmill)
|
self.read(filename, tmpDir=tmpdir, sha1sum=not force,
|
||||||
|
compress=File.xmill, sign=File.detached)
|
||||||
|
|
||||||
|
def check_signature(self, filename, repo):
|
||||||
|
tmpdir = os.path.join(ctx.config.index_dir(), repo)
|
||||||
|
File.check_signature(filename, tmpdir)
|
||||||
|
|
||||||
def index(self, repo_uri, skip_sources=False):
|
def index(self, repo_uri, skip_sources=False):
|
||||||
self.repo_dir = repo_uri
|
self.repo_dir = repo_uri
|
||||||
|
|||||||
@@ -429,9 +429,9 @@ class autoxml(oo.autosuper, oo.autoprop):
|
|||||||
|
|
||||||
if xmlfile_support:
|
if xmlfile_support:
|
||||||
def read(self, uri, keepDoc = False, tmpDir = '/tmp',
|
def read(self, uri, keepDoc = False, tmpDir = '/tmp',
|
||||||
sha1sum = False, compress = None):
|
sha1sum = False, compress = None, sign = None):
|
||||||
"read XML file and decode it into a python object"
|
"read XML file and decode it into a python object"
|
||||||
self.readxml(uri, tmpDir, sha1sum=sha1sum, compress=compress)
|
self.readxml(uri, tmpDir, sha1sum=sha1sum, compress=compress, sign=sign)
|
||||||
errs = []
|
errs = []
|
||||||
self.decode(self.rootNode(), errs)
|
self.decode(self.rootNode(), errs)
|
||||||
if hasattr(self, 'read_hook'):
|
if hasattr(self, 'read_hook'):
|
||||||
@@ -449,7 +449,7 @@ class autoxml(oo.autosuper, oo.autoprop):
|
|||||||
raise Error(*errs)
|
raise Error(*errs)
|
||||||
|
|
||||||
def write(self, uri, keepDoc = False, tmpDir = '/tmp',
|
def write(self, uri, keepDoc = False, tmpDir = '/tmp',
|
||||||
sha1sum = False, compress = None):
|
sha1sum = False, compress = None, sign = None):
|
||||||
"encode the contents of the python object into an XML file"
|
"encode the contents of the python object into an XML file"
|
||||||
errs = self.errors()
|
errs = self.errors()
|
||||||
if errs:
|
if errs:
|
||||||
@@ -463,7 +463,7 @@ class autoxml(oo.autosuper, oo.autoprop):
|
|||||||
if errs:
|
if errs:
|
||||||
errs.append(_("autoxml.write: File encoding '%s' has errors") % uri)
|
errs.append(_("autoxml.write: File encoding '%s' has errors") % uri)
|
||||||
raise Error(*errs)
|
raise Error(*errs)
|
||||||
self.writexml(uri, tmpDir, sha1sum=sha1sum, compress=compress)
|
self.writexml(uri, tmpDir, sha1sum=sha1sum, compress=compress, sign=sign)
|
||||||
if not keepDoc:
|
if not keepDoc:
|
||||||
self.unlink() # get rid of the tree
|
self.unlink() # get rid of the tree
|
||||||
|
|
||||||
|
|||||||
@@ -67,9 +67,9 @@ class XmlFile(object):
|
|||||||
"""returns root document element"""
|
"""returns root document element"""
|
||||||
return self.doc.documentElement
|
return self.doc.documentElement
|
||||||
|
|
||||||
def readxml(self, uri, tmpDir='/tmp', sha1sum=False, compress=None):
|
def readxml(self, uri, tmpDir='/tmp', sha1sum=False, compress=None, sign=None):
|
||||||
uri = File.make_uri(uri)
|
uri = File.make_uri(uri)
|
||||||
localpath = File.download(uri, tmpDir,sha1sum=sha1sum,compress=compress)
|
localpath = File.download(uri, tmpDir,sha1sum=sha1sum,compress=compress,sign=sign)
|
||||||
try:
|
try:
|
||||||
self.doc = NoExtDtdReader.parseUri(Ft.Lib.Uri.OsPathToUri(localpath))
|
self.doc = NoExtDtdReader.parseUri(Ft.Lib.Uri.OsPathToUri(localpath))
|
||||||
return self.doc.documentElement
|
return self.doc.documentElement
|
||||||
@@ -78,8 +78,8 @@ class XmlFile(object):
|
|||||||
except exceptions.ValueError, e:
|
except exceptions.ValueError, e:
|
||||||
raise Error(_("File '%s' not found") % localpath )
|
raise Error(_("File '%s' not found") % localpath )
|
||||||
|
|
||||||
def writexml(self, uri, tmpDir = '/tmp', sha1sum=False, compress=None):
|
def writexml(self, uri, tmpDir = '/tmp', sha1sum=False, compress=None, sign=None):
|
||||||
f = File(uri, File.write, sha1sum=sha1sum, compress=compress)
|
f = File(uri, File.write, sha1sum=sha1sum, compress=compress, sign=sign)
|
||||||
PrettyPrint(self.rootNode(), stream = f)
|
PrettyPrint(self.rootNode(), stream = f)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user