11import abc
22import json
3- import os . path
3+ import os
44
55from django .utils .translation import ugettext as _
66
77__author__ = 'katharine'
88
9-
9+ SRC_DIR = 'src'
1010PACKAGE_MANIFEST = 'package.json'
1111APPINFO_MANIFEST = 'appinfo.json'
1212MANIFEST_KINDS = [PACKAGE_MANIFEST , APPINFO_MANIFEST ]
@@ -33,57 +33,38 @@ def path(self):
3333 return None
3434
3535
36- def is_manifest (kind , contents ):
37- """ A potentially valid manifest is a package.json file with a "pebble" object, or an appinfo.json file. """
38- if kind == PACKAGE_MANIFEST :
39- return 'pebble' in json .loads (contents )
40- elif kind == APPINFO_MANIFEST :
41- return True
42- else :
43- return False
36+ def rank_manifest_path (dirname , kind ):
37+ """ Sort key for manifest files. Sort first by depth and add a penalty for being an appinfo.json """
38+ return os .path .normpath (dirname ).count ('/' ) + (0.5 if kind == APPINFO_MANIFEST else 0 )
4439
4540
4641def find_project_root_and_manifest (project_items ):
4742 """ Given the contents of an archive, find a valid Pebble project.
4843 :param project_items: A list of BaseProjectItems
4944 :return: A tuple of (path_to_project, manifest BaseProjectItem)
5045 """
51- SRC_DIR = 'src/'
52-
53- # Sort the paths by the number of path separators they have,
54- sorted_items = sorted (project_items , key = lambda x : os .path .normpath (x .path ).count ('/' ))
55- for i , item in enumerate (sorted_items ):
56- base_dir = item .path
57-
58- # Check if the file is one of the kinds of manifest file
59- for name in MANIFEST_KINDS :
60- dir_end = base_dir .rfind (name )
61- if dir_end == - 1 :
62- continue
63- # Ensure that the file is actually a manifest file
64- if dir_end + len (name ) == len (base_dir ):
65- if is_manifest (name , item .read ()):
66- manifest_item = item
67- break
68- else :
69- # If the file is not a manifest file, continue looking for the manfiest.
70- continue
46+ found_manifests = set ()
47+ found_src_files = set ()
7148
72- # The base dir is the location of the manifest file without the manifest filename.
73- base_dir = base_dir [:dir_end ]
74-
75- # Now check the rest of the items for a source directory containing at least one source file.
76- for source_item in sorted_items [i + 1 :]:
77- source_dir = source_item .path
78- if source_dir [:dir_end ] != base_dir :
79- continue
80- if not source_dir .endswith ('.c' ) and not source_dir .endswith ('.js' ):
81- continue
82- if source_dir [dir_end :dir_end + len (SRC_DIR )] != SRC_DIR :
83- continue
84- break
85- else :
86- # If there was no source directory with a source file, keep looking for manifest files.
49+ for item in project_items :
50+ item_path = item .path
51+
52+ # If the item looks like a manifest, add it to a set of potential manifests
53+ item_dirname , item_basename = os .path .split (item_path )
54+ if (item_basename == PACKAGE_MANIFEST and 'pebble' in json .loads (item .read ())) or item_basename == APPINFO_MANIFEST :
55+ found_manifests .add (((item_dirname , item_basename ), item ))
8756 continue
88- return base_dir , manifest_item
57+
58+ # Otherwise, add it to a set of source files if it is one.
59+ if item_path .endswith (('.c' , '.js' , '.h' )):
60+ found_src_files .add (item_path )
61+
62+ # Choose the most shallow manifest file which has a non-empty source directory.
63+ sorted_manifests = sorted (found_manifests , key = lambda x : rank_manifest_path (* x [0 ]))
64+ for (base , kind ), item in sorted_manifests :
65+ src_dir = os .path .join (base , SRC_DIR ) + os .sep
66+ for src_path in found_src_files :
67+ if src_path .startswith (src_dir ):
68+ base = base + os .sep if base else ""
69+ return base , item
8970 raise InvalidProjectArchiveException (_ ("No project root found." ))
0 commit comments