#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Reduce a toolchain to the bare minimum required set of files.
"""
from __future__ import print_function, with_statement

import sys
import os
import tempfile
import subprocess
import shutil
import argparse
from contextlib import contextmanager

@contextmanager
def tempdir():
    """
    Context manager to create a temporary directory and ensure it's
    removed completely when we're done
    """
    dirname = tempfile.mkdtemp()
    yield dirname
    try:
        shutil.rmtree(dirname)
    except OSError as exc:
        if exc.errno != errno.ENOENT:
            raise

def strace_iter(*args):
    """
    Perform the strace and then yields each line of the recorded
    strace
    """
    with tempdir() as dirname:
        opfile = os.path.join(dirname, "strace_output.log")

        cmd = ["strace", "-f", "-e", "trace=open,execve", "-o", "%s" % opfile]
        cmd.extend(args)
        print("Running: %s" % " ".join(cmd))
        try:
            subprocess.check_call(cmd)
        except subprocess.CalledProcessError as exc:
            print(repr(exc))

        with open(opfile, 'r') as strace:
            for line in strace:
                yield line

def reduct(source, destination, *args):
    """
    Perform the reduct

    Args:
        source (string): The source directory containing the tool to reduce

        destination (string): Where to copy the reduced toolchain to
    """
    def copy_full(sourcefile):
        chunk = sourcefile[len(source):].lstrip("/")
        dirname = os.path.dirname(chunk)
        target = os.path.join(destination, dirname)
        if not os.path.isdir(target):
            os.makedirs(target)
        if not os.path.isfile(os.path.join(target, os.path.split(chunk)[-1])):
            print("Copying %s" % sourcefile)
            shutil.copy2(sourcefile, target)

    def make_link(sourcelink):
        print("Here we would make a softlink from %s to %s" % (
             sourcelink, os.path.realpath(sourcelink)))
        #link_target = os.path.realpath(sourcelink)
    



    if not os.path.isdir(destination):
        os.makedirs(destination)

    print("Executing: %s" % (" ".join(args)))

    for line in strace_iter(*args):
        try:
            syscall = line.split()[1]
        except IndexError:
            break
        path = syscall[syscall.find("\"")+1:syscall.rfind("\"")]
        path = os.path.abspath(path)
        if not os.path.isfile(path):
            continue
        if path.startswith(source):
            if os.path.islink(path):
                make_link(path)
            else:
                copy_full(path)


def main(argv=sys.argv[1:]):
    parser = argparse.ArgumentParser()
    parser.add_argument('--source', dest='source', type=str, required=True,
                   help='Source directory containing the tool')
    parser.add_argument('--dest', dest='dest', type=str, required=True,
                   help='Destination directory for the redacted tool')
    args, extra = parser.parse_known_args(args=argv)

    if not os.path.isdir(args.source):
        parser.print_help()
        sys.exit(1)

    reduct(args.source, args.dest, *extra)

if __name__ == "__main__":
    main()


@@ -880,16 +880,23 @@
 n,execve
+,access
 %22, %22-o%22,
@@ -1914,105 +1914,720 @@
     
-print(%22Here we would make a softlink from %25s to %25s%22 %25 (%0A             sourcelink, os.path.realpath
+link_target = os.path.realpath(sourcelink)%0A%0A        # First of all ensure the target exists%0A        if link_target.startswith(source):%0A            handle_file(link_target)%0A%0A        # Extract the common prefix and create a relative symlink%0A        chunk = sourcelink%5Blen(source):%5D.lstrip(%22/%22)%0A        dirname = os.path.dirname(chunk)%0A        target = os.path.join(destination, dirname)%0A        filename = os.path.split(sourcelink)%5B-1%5D%0A        link_name = os.path.join(os.path.join(destination, dirname), filename)%0A%0A        if not os.path.isdir(target):%0A            os.makedirs(target)%0A%0A        new_target_dir = os.path.relpath(os.path.dirname(link_target),%0A                                         os.path.dirname
 (sou
@@ -2635,17 +2635,16 @@
 celink))
-)
 %0A       
@@ -2648,13 +2648,11 @@
     
-#link
+new
 _tar
@@ -2669,35 +2669,356 @@
 ath.
-realpath(sourcelink)%0A    %0A%0A
+join(new_target_dir, os.path.split(link_target)%5B-1%5D)%0A        if not os.path.isfile(link_name):%0A            print(%22Making softlink from %25s -%3E %25s%22 %25 (link_name, new_target))%0A            os.symlink(new_target, link_name)%0A%0A    def handle_file(path):%0A        if os.path.islink(path):%0A            make_link(path)%0A        else:%0A            copy_full(path)
 %0A%0A  
@@ -3479,108 +3479,19 @@
     
-if os.path.islink(path):%0A                make_link(path)%0A            else:%0A                copy_full
+handle_file
 (pat
@@ -3495,16 +3495,17 @@
 path)%0A%0A%0A
+%0A
 def main
@@ -3834,17 +3834,17 @@
  the red
-a
+u
 cted too

Fix softlinks, also trap "access" system calls too