diff options
Diffstat (limited to 'ipsutils')
-rw-r--r-- | ipsutils/tasks.py | 174 |
1 files changed, 112 insertions, 62 deletions
diff --git a/ipsutils/tasks.py b/ipsutils/tasks.py index ae6ecb4..d376f38 100644 --- a/ipsutils/tasks.py +++ b/ipsutils/tasks.py @@ -14,8 +14,12 @@ # along with ipsutils. If not, see <http://www.gnu.org/licenses/>.
from . import task
from . import tpl
+from collections import OrderedDict
+import grp
import os
+import pwd
import string
+import shlex
import shutil
import subprocess
import sys
@@ -27,21 +31,21 @@ import zipfile class Lint(task.Task):
def __init__(self, *args, **kwargs):
"""Execute LINT engine.
- In order to facility continued use, a cache directory is created
- in the user's home directory to store pkglint manifests. There is
- *nothing* fast about pkglint (even with the cache).
+ In order to facility continued use, a cache directory is created
+ in the user's home directory to store pkglint manifests. There is
+ *nothing* fast about pkglint (even with the cache).
"""
super(Lint, self).__init__(self, *args, **kwargs)
self.name = "Package LINT checking (this may take a while...)"
self.cachedir = os.path.join(os.environ['HOME'], '.ipscache')
-
+
def _check_cache(self):
if not os.path.exists(self.cachedir):
print("Creating cache directory: {0:s}".format(self.cachedir))
os.mkdir(self.cachedir)
return False
return True
-
+
def _create_cache(self):
command_pkg = [self.cls.tool['pkglint'],
'-c',
@@ -50,14 +54,14 @@ class Lint(task.Task): 'http://pkg.oracle.com/solaris/release/',
self.cls.env_meta['STAGE4']]
print("Creating cache (this may take a while...)")
- proc_pkg = subprocess.Popen(command_pkg, stderr=subprocess.STDOUT)
+ proc_pkg = subprocess.Popen(command_pkg, stderr=subprocess.STDOUT)
err = proc_pkg.wait()
return err
-
+
def task(self):
if not self._check_cache():
self._create_cache()
-
+
command_pkg = [self.cls.tool['pkglint'],
'-c',
self.cachedir,
@@ -65,8 +69,8 @@ class Lint(task.Task): proc_pkg = subprocess.Popen(command_pkg, stderr=subprocess.STDOUT)
err = proc_pkg.wait()
return err
-
-
+
+
class Resolve_Dependencies(task.Task):
def __init__(self, *args, **kwargs):
"""Automatically resolve dependencies.
@@ -74,7 +78,7 @@ class Resolve_Dependencies(task.Task): """
super(Resolve_Dependencies, self).__init__(self, *args, **kwargs)
self.name = "Dependency resolution"
-
+
def task(self):
command_pkg = [self.cls.tool['pkgdepend'],
'resolve',
@@ -99,19 +103,12 @@ class Dependencies(task.Task): '-md',
self.cls.env_pkg['BUILDPROTO'],
self.cls.env_meta['STAGE1_PASS2']]
- command_pkgfmt = [self.cls.tool['pkgfmt']]
fp = file(self.cls.env_meta['STAGE3'], 'w+')
- proc_pkg = subprocess.Popen(command_pkg,
- stdout=subprocess.PIPE)
- proc_pkgfmt = subprocess.Popen(command_pkgfmt,
- stdin=proc_pkg.stdout,
- stdout=fp)
- output, err = proc_pkgfmt.communicate()
+ proc_pkg = subprocess.Popen(command_pkg, stdout=fp)
+ err = proc_pkg.wait()
fp.close()
- if self.cls.options.verbose:
- if output:
- for line in output:
- print(">>> {0:s}".format(line))
+ if err <= 1:
+ err = 0
return err
@@ -119,8 +116,8 @@ class Transmogrify(task.Task): def __init__(self, *args, **kwargs):
"""Using pkgmogrify's format in %transforms, a user may define
specific file modifications on the package manifest
-
- For specification see:
+
+ For specification see:
man pkgmogrify(1)
"""
super(Transmogrify, self).__init__(self, *args, **kwargs)
@@ -131,7 +128,6 @@ class Transmogrify(task.Task): '-DARCH={0:s}'.format(self.cls.key_dict['arch']),
self.cls.env_meta['STAGE1'],
self.cls.env_meta['STAGE2']]
- command_pkgfmt = [self.cls.tool['pkgfmt']]
fp = file(self.cls.env_meta['STAGE2'], 'w+')
# Write %transforms block into transmogrification file
# Proper syntax required.
@@ -141,18 +137,9 @@ class Transmogrify(task.Task): fp.close()
fp = file(self.cls.env_meta['STAGE1_PASS2'], 'w+')
- proc_pkg = subprocess.Popen(command_pkg,
- stdout=subprocess.PIPE)
- proc_pkgfmt = subprocess.Popen(command_pkgfmt,
- stdin=proc_pkg.stdout,
- stdout=fp)
- output, err = proc_pkgfmt.communicate()
+ proc_pkg = subprocess.Popen(command_pkg, stdout=fp)
+ err = proc_pkg.wait()
fp.close()
-
- if self.cls.options.verbose:
- if output:
- for line in output:
- print(">>> {0:s}".format(line))
return err
@@ -162,24 +149,15 @@ class Manifest(task.Task): """
super(Manifest, self).__init__(self, *args, **kwargs)
self.name = "Generate file manifest"
-
+
def task(self):
command_pkg = [self.cls.tool['pkgsend'],
'generate',
self.cls.env_pkg['BUILDPROTO']]
- command_pkgfmt = [self.cls.tool['pkgfmt']]
fp = file(self.cls.env_meta['STAGE1'], 'a')
- proc_pkg = subprocess.Popen(command_pkg,
- stdout=subprocess.PIPE)
- proc_pkgfmt = subprocess.Popen(command_pkgfmt,
- stdin=proc_pkg.stdout,
- stdout=fp)
- output, err = proc_pkgfmt.communicate()
+ proc_pkg = subprocess.Popen(command_pkg, stdout=fp)
+ err = proc_pkg.wait()
fp.close()
- if self.cls.options.verbose:
- if output:
- for line in output:
- print(">>> {0:s}".format(line))
return err
@@ -198,14 +176,14 @@ class Unpack(task.Task): archive.extractall(dest)
archive.close()
return True
-
+
def unzip(self, src, dest):
if not zipfile.is_zipfile(src):
return False
archive = zipfile.ZipFile(src)
archive.extractall(dest)
return True
-
+
def task(self):
path = os.path.abspath(self.cls.env_pkg['SOURCES'])
if not os.path.exists(path):
@@ -232,10 +210,10 @@ class Unpack(task.Task): class Buildroot(task.Task):
def __init__(self, *args, **kwargs):
"""Destroy/Create BUILDROOT per execution to keep the environment stable
- """
+ """
super(Buildroot, self).__init__(self, *args, **kwargs)
self.name = "Create build root"
-
+
def task(self):
path = self.cls.env_pkg['BUILDROOT']
if os.path.exists(path):
@@ -251,7 +229,7 @@ class Metadata(task.Task): """
super(Metadata, self).__init__(self, *args, **kwargs)
self.name = "Generate meta data"
-
+
def task(self):
# A common problem that needs solving. What if you need to name your
# package something else? "repackage"
@@ -259,7 +237,7 @@ class Metadata(task.Task): repackas = 'repackage'
else:
repackas = 'name'
-
+
output = []
meta_map = {
'pkg.fmri': self.cls.key_dict['group'] + "/" +
@@ -286,7 +264,7 @@ class Metadata(task.Task): metadata = file(os.path.join(self.cls.env_meta['STAGE1']), 'w+')
for line in output:
if self.cls.options.verbose:
- print(">>> {0:s}".format(line))
+ print(">>> {0:s}".format(line))
metadata.writelines(line)
metadata.close()
return True
@@ -301,7 +279,7 @@ class Script(task.Task): """
super(Script, self).__init__(self, *args, **kwargs)
self.script = script
-
+
def task(self):
shebang = "#!/bin/bash\n"
fp_tempfile = tempfile.NamedTemporaryFile('w+', prefix='ipsutils_', suffix='.sh', delete=True)
@@ -324,7 +302,7 @@ class Script(task.Task): proc = subprocess.Popen(script, stdout=sys.stdout)
err = proc.wait()
fp_tempfile.close()
-
+
os.chdir(self.cls.env['IPSBUILD'])
return err
@@ -337,7 +315,7 @@ class Package(task.Task): is a need.
"""
super(Package, self).__init__(self, *args, **kwargs)
- self.name = "Generate package"
+ self.name = "Generate package"
self.spkg = False
self.source = self.cls.env_pkg['BUILDROOT']
self.destination = self.cls.env_pkg['PKGS']
@@ -345,11 +323,11 @@ class Package(task.Task): self.spkg = True
self.name = "Generate source package"
self.destination = self.cls.env_pkg['SPKGS']
-
+
def task(self):
if os.path.exists(self.destination):
shutil.rmtree(self.destination)
-
+
if self.spkg:
os.mkdir(self.destination)
shutil.copy2(self.cls.ipsfile, self.destination)
@@ -359,6 +337,78 @@ class Package(task.Task): os.path.join(self.destination, \
os.path.basename(self.cls.env_pkg['BUILDPROTO'])))
shutil.copy2(self.cls.env_meta['STAGE4'], self.destination)
-
- return 0
+ return 0
+
+class AlignPermissions(task.Internal):
+ def __init__(self, *args, **kwargs):
+ """Reduces the need for manual transmogrification.
+ IPS ability to generate a manifest that is compatible with itself is
+ incredibly bad. Permissions in a manifest never match the system's
+ directory permissions.
+
+ In order to fix the situation we reference the manifest permissions and
+ the system permissions, then replace the incorrect lines with the
+ proper values.
+ """
+ super(AlignPermissions, self).__init__(self, *args, **kwargs)
+ self.name = "Automatic permission alignment"
+ self.filename = self.cls.env_meta['STAGE4']
+
+ def task(self):
+ system_paths = []
+ manifest_paths = []
+ corrections = []
+
+ line_number = 1
+ for line in file(self.filename):
+ if line.startswith('dir'):
+ line = line.lstrip('dir')
+ tokens = shlex.split(line)
+ path = OrderedDict()
+ for token in tokens:
+ s = token.split('=')
+ path[s[0]] = s[1]
+ path['line'] = line_number
+ manifest_paths.append(path)
+ line_number += 1
+
+ # Check manifest real paths against the real system paths
+ # Rewrite manifest with the proper system-level permissions to prevent the
+ # IPS from bombing upon installing simple packages with slightly different
+ # permissions.
+ for path in manifest_paths:
+ for k, v in path.items():
+ if 'path' in k:
+ real = os.path.join('/', v)
+ try:
+ si = os.stat(os.path.realpath(real))
+ owner = pwd.getpwuid(si.st_uid).pw_name
+ group = grp.getgrgid(si.st_gid).gr_name
+ mode = si.st_mode & 0777
+ replacement = 'dir {}={} owner={} group={} mode={}'.format(k, v, owner, group, oct(mode))
+ self.corrections.append({path['line']: replacement})
+ except:
+ continue
+ line_number = 1
+ found = False
+ infile = file(self.filename, 'r')
+ outfile = tempfile.NamedTemporaryFile(delete=True)
+
+ for line in infile.readlines():
+ for correction in corrections:
+ for pos, key in correction.items():
+ if line_number == pos:
+ found = True
+ if self.cls.options.verbose:
+ print("Correcting line WANT:{}, GOT:{}".format(line_number, pos))
+ outfile.write(key + '\n')
+ if not found:
+ outfile.writelines(line)
+ else:
+ found = False
+ line_number += 1
+
+ infile.close()
+ shutil.copyfile(outfile.name, self.filename)
+ outfile.close()
|