<div dir="ltr">For some recipes (llvm, chromium, chromium-wayland) I&#39;ve noticed this function to fail with:<div><br></div><div><pre style="box-sizing:border-box;white-space:pre-wrap;word-wrap:break-word;margin-top:0px;margin-bottom:0px;color:rgb(51,51,51);font-size:14px">ERROR: llvm3.3-3.3-r0 do_unpack: Error executing a python function in exec_python_func() autogenerated:

The stack trace of python calls that resulted in this exception/failure was:
File: &#39;exec_python_func() autogenerated&#39;, lineno: 2, function: &lt;module&gt;
     0001:
 *** 0002:base_do_unpack(d)
     0003:
File: &#39;/home/jenkins/oe/world/shr-core/openembedded-core/meta/classes/base.bbclass&#39;, lineno: 215, function: base_do_unpack
     0211:
     0212:    try:
     0213:        fetcher = bb.fetch2.Fetch(src_uri, d)
     0214:        fetcher.unpack(d.getVar(&#39;WORKDIR&#39;))
 *** 0215:        create_src_date_epoch_stamp(d)
     0216:    except bb.fetch2.BBFetchException as e:
     0217:        bb.fatal(str(e))
     0218:}
     0219:
File: &#39;/home/jenkins/oe/world/shr-core/openembedded-core/meta/classes/base.bbclass&#39;, lineno: 34, function: create_src_date_epoch_stamp
     0030:            exclude = set([&quot;temp&quot;, &quot;licenses&quot;, &quot;patches&quot;, &quot;recipe-sysroot-native&quot;, &quot;recipe-sysroot&quot; ])
     0031:            for root, dirs, files in os.walk(path, topdown=True):
     0032:                dirs[:] = [d for d in dirs if d not in exclude]
     0033:                if root.endswith(&#39;/git&#39;):
 *** 0034:                    src_date_epoch = get_git_src_date_epoch(d, root)
     0035:                    break
     0036:
     0037:                for fname in files:
     0038:                    filename = os.path.join(root, fname)
File: &#39;/home/jenkins/oe/world/shr-core/openembedded-core/meta/classes/base.bbclass&#39;, lineno: 17, function: get_git_src_date_epoch
     0013:def get_git_src_date_epoch(d, path):
     0014:    import subprocess
     0015:    saved_cwd = os.getcwd()
     0016:    os.chdir(path)
 *** 0017:    src_date_epoch = int(subprocess.check_output([&#39;git&#39;,&#39;log&#39;,&#39;-1&#39;,&#39;--pretty=%ct&#39;]))
     0018:    os.chdir(saved_cwd)
     0019:    return src_date_epoch
     0020:
     0021:def create_src_date_epoch_stamp(d):
File: &#39;/usr/lib/python3.5/subprocess.py&#39;, lineno: 626, function: check_output
     0622:        # empty string. That is maintained here for backwards compatibility.
     0623:        kwargs[&#39;input&#39;] = &#39;&#39; if kwargs.get(&#39;universal_newlines&#39;, False) else b&#39;&#39;
     0624:
     0625:    return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
 *** 0626:               **kwargs).stdout
     0627:
     0628:
     0629:class CompletedProcess(object):
     0630:    &quot;&quot;&quot;A process that has finished running.
File: &#39;/usr/lib/python3.5/subprocess.py&#39;, lineno: 708, function: run
     0704:            raise
     0705:        retcode = process.poll()
     0706:        if check and retcode:
     0707:            raise CalledProcessError(retcode, process.args,
 *** 0708:                                     output=stdout, stderr=stderr)
     0709:    return CompletedProcess(process.args, retcode, stdout, stderr)
     0710:
     0711:
     0712:def list2cmdline(seq):
Exception: subprocess.CalledProcessError: Command &#39;[&#39;git&#39;, &#39;log&#39;, &#39;-1&#39;, &#39;--pretty=%ct&#39;]&#39; returned non-zero exit status 128

ERROR: llvm3.3-3.3-r0 do_unpack: Function failed: base_do_unpack
ERROR: Logfile of failure stored in: /home/jenkins/oe/world/shr-core/tmp-glibc/work/i586-oe-linux/llvm3.3/3.3-r0/temp/log.do_unpack.25005
NOTE: recipe llvm3.3-3.3-r0: task do_unpack: Failed
ERROR: Task (/home/jenkins/oe/world/shr-core/meta-openembedded/meta-oe/recipes-core/llvm/llvm3.3_3.3.bb:do_unpack) failed with exit code &#39;1&#39;</pre><pre style="box-sizing:border-box;white-space:pre-wrap;word-wrap:break-word;margin-top:0px;margin-bottom:0px;color:rgb(51,51,51);font-size:14px"><br></pre><pre style="box-sizing:border-box;white-space:pre-wrap;word-wrap:break-word;margin-top:0px;margin-bottom:0px;color:rgb(51,51,51);font-size:14px">Maybe I don&#39;t have the latest version of this patch (I&#39;m not using your poky-contrib branch yet), but it should fail with nicer message when git log fails for whatever reason.</pre></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, May 1, 2017 at 10:59 PM, Juro Bystricky <span dir="ltr">&lt;<a href="mailto:juro.bystricky@intel.com" target="_blank">juro.bystricky@intel.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Conditionally set some environment variables in order to achieve<br>
improved binary reproducibility. Providing BUILD_REPRODUCIBLE_BINARIES is<br>
set to &quot;1&quot;, we set the following environment variables:<br>
<br>
export PYTHONHASHSEED=0<br>
export PERL_HASH_SEED=0<br>
export TZ=&quot;UTC&quot;<br>
<br>
We also export and set SOURCE_DATE_EPOCH. The value for this variable<br>
is obtained after source code for a recipe has been unpacked, but before it is<br>
patched. If the code comes from a GIT repo, we get the timestamp from the top<br>
commit. (This usually corresponds to the mktime of &quot;changelog&quot;.)<br>
Otherwise we go through all files and get the timestamp from the youngest<br>
one. We create a timestamp for each recipe. The timestamp is stored in the file<br>
&#39;src_date_epoch.txt&#39;. Later on, each task reads this file and sets SOURCE_DATE_EPOCH<br>
based on the value found in the file.<br>
<br>
[YOCTO#11178]<br>
[YOCTO#11179]<br>
<br>
Signed-off-by: Juro Bystricky &lt;<a href="mailto:juro.bystricky@intel.com">juro.bystricky@intel.com</a>&gt;<br>
---<br>
 meta/classes/base.bbclass | 82 ++++++++++++++++++++++++++++++<wbr>+++++++++++++++++<br>
 1 file changed, 82 insertions(+)<br>
<br>
diff --git a/meta/classes/base.bbclass b/meta/classes/base.bbclass<br>
index e29821f..f2b2d97 100644<br>
--- a/meta/classes/base.bbclass<br>
+++ b/meta/classes/base.bbclass<br>
@@ -10,6 +10,52 @@ inherit utility-tasks<br>
 inherit metadata_scm<br>
 inherit logging<br>
<br>
+def get_git_src_date_epoch(d, path):<br>
+    import subprocess<br>
+    saved_cwd = os.getcwd()<br>
+    os.chdir(path)<br>
+    src_date_epoch = int(subprocess.check_output([&#39;<wbr>git&#39;,&#39;log&#39;,&#39;-1&#39;,&#39;--pretty=%ct&#39;<wbr>]))<br>
+    os.chdir(saved_cwd)<br>
+    return src_date_epoch<br>
+<br>
+def create_src_date_epoch_stamp(d)<wbr>:<br>
+    if d.getVar(&#39;BUILD_REPRODUCIBLE_<wbr>BINARIES&#39;) == &#39;1&#39;:<br>
+        path = d.getVar(&#39;S&#39;)<br>
+        src_date_epoch = 0<br>
+        filename_dbg = None<br>
+<br>
+        if path.endswith(&#39;/git&#39;):<br>
+            src_date_epoch = get_git_src_date_epoch(d, path)<br>
+        else:<br>
+            exclude = set([&quot;temp&quot;, &quot;licenses&quot;, &quot;patches&quot;, &quot;recipe-sysroot-native&quot;, &quot;recipe-sysroot&quot; ])<br>
+            for root, dirs, files in os.walk(path, topdown=True):<br>
+                dirs[:] = [d for d in dirs if d not in exclude]<br>
+                if root.endswith(&#39;/git&#39;):<br>
+                    src_date_epoch = get_git_src_date_epoch(d, root)<br>
+                    break<br>
+<br>
+                for fname in files:<br>
+                    filename = os.path.join(root, fname)<br>
+                    try:<br>
+                        mtime = int(os.path.getmtime(filename)<wbr>)<br>
+                    except:<br>
+                        mtime = 0<br>
+                    if mtime &gt; src_date_epoch:<br>
+                        src_date_epoch = mtime<br>
+                        filename_dbg = filename<br>
+<br>
+        # Most likely an empty folder<br>
+        if src_date_epoch == 0:<br>
+            bb.warn(&quot;Unable to determine src_date_epoch! path:%s&quot; % path)<br>
+<br>
+        f = open(os.path.join(path,&#39;src_<wbr>date_epoch.txt&#39;), &#39;w&#39;)<br>
+        f.write(str(src_date_epoch))<br>
+        f.close()<br>
+<br>
+        if filename_dbg != None:<br>
+            bb.debug(1,&quot; src_date_epoch %d derived from: %s&quot; % (src_date_epoch, filename_dbg))<br>
+<br>
+<br>
 OE_IMPORTS += &quot;os sys time oe.path oe.utils oe.types oe.package oe.packagegroup oe.sstatesig oe.lsb oe.cachedpath oe.license&quot;<br>
 OE_IMPORTS[type] = &quot;list&quot;<br>
<br>
@@ -173,6 +219,7 @@ python base_do_unpack() {<br>
     try:<br>
         fetcher = bb.fetch2.Fetch(src_uri, d)<br>
         fetcher.unpack(d.getVar(&#39;<wbr>WORKDIR&#39;))<br>
+        create_src_date_epoch_stamp(d)<br>
     except bb.fetch2.BBFetchException as e:<br>
         bb.fatal(str(e))<br>
 }<br>
@@ -383,9 +430,43 @@ def set_packagetriplet(d):<br>
<br>
     settriplet(d, &quot;PKGMLTRIPLETS&quot;, archs, tos, tvs)<br>
<br>
+<br>
+export PYTHONHASHSEED<br>
+export PERL_HASH_SEED<br>
+export SOURCE_DATE_EPOCH<br>
+<br>
+BB_HASHBASE_WHITELIST += &quot;SOURCE_DATE_EPOCH PYTHONHASHSEED PERL_HASH_SEED &quot;<br>
+<br>
 python () {<br>
     import string, re<br>
<br>
+    # Create reproducible_environment<br>
+<br>
+    if d.getVar(&#39;BUILD_REPRODUCIBLE_<wbr>BINARIES&#39;) == &#39;1&#39;:<br>
+        import subprocess<br>
+        d.setVar(&#39;PYTHONHASHSEED&#39;, &#39;0&#39;)<br>
+        d.setVar(&#39;PERL_HASH_SEED&#39;, &#39;0&#39;)<br>
+        d.setVar(&#39;TZ&#39;, &#39;UTC&#39;)<br>
+<br>
+        path = d.getVar(&#39;S&#39;)<br>
+        epochfile = os.path.join(path,&#39;src_date_<wbr>epoch.txt&#39;)<br>
+        if os.path.isfile(epochfile):<br>
+            f = open(epochfile, &#39;r&#39;)<br>
+            src_date_epoch = f.read()<br>
+            f.close()<br>
+            bb.debug(1, &quot;src_date_epoch stamp found ---&gt; stamp %s&quot; % src_date_epoch)<br>
+            d.setVar(&#39;SOURCE_DATE_EPOCH&#39;, src_date_epoch)<br>
+        else:<br>
+            bb.debug(1, &quot;src_date_epoch stamp not found.&quot;)<br>
+            d.setVar(&#39;SOURCE_DATE_EPOCH&#39;, &#39;0&#39;)<br>
+    else:<br>
+        if &#39;PYTHONHASHSEED&#39; in os.environ:<br>
+            del os.environ[&#39;PYTHONHASHSEED&#39;]<br>
+        if &#39;PERL_HASH_SEED&#39; in os.environ:<br>
+            del os.environ[&#39;PERL_HASH_SEED&#39;]<br>
+        if &#39;SOURCE_DATE_EPOCH&#39; in os.environ:<br>
+            del os.environ[&#39;SOURCE_DATE_EPOCH&#39;<wbr>]<br>
+<br>
     # Handle PACKAGECONFIG<br>
     #<br>
     # These take the form:<br>
@@ -678,6 +759,7 @@ python () {<br>
             bb.warn(&quot;Recipe %s is marked as only being architecture specific but seems to have machine specific packages?! The recipe may as well mark itself as machine specific directly.&quot; % d.getVar(&quot;PN&quot;))<br>
 }<br>
<br>
+<br>
 addtask cleansstate after do_clean<br>
 python do_cleansstate() {<br>
         sstate_clean_cachefiles(d)<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.7.4<br>
<br>
</font></span></blockquote></div><br></div>