dep_tracker: Decode file types.

This patch introduces a new library module named filetype that decodes
the type of a file based on the contents, metadata and filename. It
provides a hierarchy of file types based on the file contents, name
and other metadata. In some cases, the filetype uses the mime type
detected from the magic database, but in many other cases the mime
type is not descriptive enough. For example, all the ELF files will
have the same mime type, while this module further differenciates
them between static, dynamically linked and .so libraries.

This new module is used from dep_tracker to compute the file type
information.

BUG=chromium:381830
TEST=Unittest added for several file types.
TEST=`sudo dep_tracker path/to/rootfs --json output.json` has the ftype field on every file.

Change-Id: Icab98897ca7e948e2620743597b9268aef1709a6
Reviewed-on: https://chromium-review.googlesource.com/216381
Tested-by: Alex Deymo <deymo@chromium.org>
Reviewed-by: Mike Frysinger <vapier@chromium.org>
Commit-Queue: Alex Deymo <deymo@chromium.org>
diff --git a/scripts/dep_tracker_unittest.py b/scripts/dep_tracker_unittest.py
index 64eadd8..d098ca8 100755
--- a/scripts/dep_tracker_unittest.py
+++ b/scripts/dep_tracker_unittest.py
@@ -11,6 +11,7 @@
 sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)),
                                 '..', '..'))
 from chromite.lib import cros_test_lib
+from chromite.lib import osutils
 from chromite.lib import unittest_lib
 from chromite.scripts import dep_tracker
 
@@ -50,6 +51,26 @@
 
     self.assertEquals(sorted(dt._files.keys()), ['abc_main', 'libabc.so'])
 
+  def testFiletypeSet(self):
+    """Tests that the 'ftype' member is set for ELF files first."""
+    unittest_lib.BuildELF(os.path.join(self.tempdir, 'libabc.so'),
+                          ['func_a', 'func_b', 'func_c'])
+    osutils.WriteFile(os.path.join(self.tempdir, 'pyscript'),
+                      "#!/usr/bin/python\nimport sys\nsys.exit(42)\n")
+    dt = dep_tracker.DepTracker(self.tempdir)
+    dt.Init()
+
+    # ComputeELFFileDeps() should compute the file type of ELF files so we
+    # don't need to parse them again.
+    dt.ComputeELFFileDeps()
+    self.assertTrue('ftype' in dt._files['libabc.so'])
+    self.assertFalse('ftype' in dt._files['pyscript'])
+
+    # ComputeFileTypes() shold compute the file type of every file.
+    dt.ComputeFileTypes()
+    self.assertTrue('ftype' in dt._files['libabc.so'])
+    self.assertTrue('ftype' in dt._files['pyscript'])
+
 
 if __name__ == '__main__':
   cros_test_lib.main()