Refactoring of stage and *DEPENDS handling and add fstage/FDEPENDS
[oe-lite:cbss-base.git] / classes / stage.oeclass
1 # -*- mode:python; -*-
2
3 inherit binconfig-stage
4 inherit libtool-stage
5 addtask stage
6
7 do_stage[cleandirs]     = "${STAGE_DIR} ${STAGE_DIR}.unpack"
8 do_stage[dirs]          = "${STAGE_DIR}"
9 do_stage[recdeptask]    = "DEPENDS:do_package"
10
11 do_stage[import] = "set_stage"
12 def do_stage(d):
13     def get_dstdir(cwd, package):
14         return os.path.join(cwd, package.type)
15     return set_stage(d, "__stage", "STAGE_FIXUP_FUNCS", get_dstdir,
16                      d.get("STAGE_DIR") + ".unpack")
17
18 set_stage[emit] += "do_stage"
19
20 def set_stage(d, stage, stage_fixup_funcs, get_dstdir, unpackdir):
21     import tempfile
22     from oelite.util import TarFile
23     from oebakery import debug, info, warn, err, die
24
25     cwd = os.getcwd()
26
27     def update_file_priority(file_priorities, f, pkgname, dstdir):
28         f = os.path.join("/", f)
29         file_priority = None
30         fpfn = os.path.join(dstdir, pkgmetadir, pkgname, "file_priority")
31         if os.path.exists(fpfn):
32             with open(fpfn) as fpfile:
33                 fps = fpfile.readline().strip()
34             for fp in fps.split():
35                 fp = fp.rsplit(":", 1)
36                 if len(fp) == 1:
37                     if file_priority is None:
38                         file_priority = fp[0]
39                 else:
40                     if f == fp[0]:
41                         file_priority = fp[1]
42             file_priority = int(file_priority)
43         if file_priority is None:
44             file_priority = 0
45         try:
46             file_priorities[file_priority].append(pkgname)
47         except KeyError:
48             file_priorities[file_priority] = [pkgname]
49         return
50
51     def file_in_tarball(f, tarfn):
52         tf = TarFile(tarfn)
53         try:
54             return tf.getmember(f)
55         except KeyError:
56             return None
57
58     stage = d.get(stage)
59     stage_files = stage.keys()
60     stage_files.sort()
61     staged_packages = []
62     for filename in stage_files:
63         package = stage[filename]
64         if not os.path.isfile(filename):
65             die("could not find stage file: %s"%(filename))
66         dstdir = get_dstdir(cwd, package)
67         print "unpacking %s to %s"%(filename, unpackdir)
68         bb.utils.mkdirhier(unpackdir)
69         os.chdir(unpackdir)
70         with TarFile(filename, debug=0, errorlevel=1) as tf:
71             tf.extractall()
72
73         d["STAGE_FIXUP_PKG_TYPE"] = package.type
74         for funcname in (d.get(stage_fixup_funcs) or "").split():
75             print "Running", stage_fixup_funcs, funcname
76             function = d.get_function(funcname)
77             if not function.run(unpackdir):
78                 return False
79         del d["STAGE_FIXUP_PKG_TYPE"]
80
81         bb.utils.mkdirhier(dstdir)
82
83         pkgmetadir = d.get("pkgmetadir").lstrip("/")
84         dst_pkgmetadir = os.path.join(dstdir, pkgmetadir, package.name)
85         if os.path.exists(pkgmetadir):
86             os.renames(pkgmetadir, dst_pkgmetadir)
87
88         conflicts = False
89         for root, dirs, files in os.walk("."):
90             root = root[2:]
91             merged_dirs = []
92             for f in dirs:
93                 if root == "" and f == pkgmetadir:
94                     dirs.remove(f)
95                     continue
96                 srcfile = os.path.join(root, f)
97                 dstfile = os.path.join(dstdir, srcfile)
98                 if os.path.isdir(dstfile):
99                     # FIXME: check if owner/group/perms match
100                     #   on different owner/group/perms, check FILE_PRIORITY
101                     #   vars if one of them should be preserved, and if not
102                     #   fail out with a conflict
103                     continue
104                 if os.path.exists(dstfile):
105                     bb.error("file exist in stage: %s" % dstfile)
106                     # FIXME: need more descriptive error message
107                     conflicts = True
108                 os.renames(srcfile, dstfile)
109                 merged_dirs.append(f)
110             dirs = list(set(dirs).difference(set(merged_dirs)))
111             for f in files:
112                 srcfile = os.path.join(root, f)
113                 dstfile = os.path.join(dstdir, srcfile)
114                 if os.path.exists(dstfile):
115                     file_priorities = {}
116                     update_file_priority(file_priorities, srcfile,
117                                          package.name, dstdir)
118
119                     for (pkgtarfn, pkgname, pkgdstdir) in staged_packages:
120                         if pkgdstdir != dstdir:
121                             continue
122                         if file_in_tarball(os.path.join(".", root, f),
123                                            pkgtarfn):
124                             update_file_priority(file_priorities, srcfile,
125                                                  pkgname, pkgdstdir)
126
127                     priority = None
128                     priorities = file_priorities.keys()
129                     if priorities:
130                         priorities.sort()
131                         priority = priorities[-1]
132                     else:
133                         bb.error("file conflict in stage (1): /%s"%(srcfile))
134                         conflicts = True
135                         continue
136                     if len(file_priorities[priority]) != 1:
137                         bb.error("file conflict in stage (2): /%s"%(srcfile))
138                         conflicts = True
139                         continue
140                     bb.debug("priority overwrite of stage file: /%s"%(srcfile))
141                     if file_priorities[priority][0] != package.name:
142                         continue
143                     print "overwriting with %s from %s"%(srcfile, package.name)
144
145                 # FIXME: check if owner/group/perms match
146                 os.renames(srcfile, dstfile)
147         if conflicts:
148             bb.fatal("file conflicts in stage")
149
150         os.chdir(dstdir)
151         shutil.rmtree(unpackdir)
152
153         staged_packages.append((filename, package.name, dstdir))
154
155 STAGE_FIXUP_FUNCS ?= ""