1
1
import abc
2
2
import json
3
- import os . path
3
+ import os
4
4
5
5
from django .utils .translation import ugettext as _
6
6
7
7
__author__ = 'katharine'
8
8
9
-
9
+ SRC_DIR = 'src'
10
10
PACKAGE_MANIFEST = 'package.json'
11
11
APPINFO_MANIFEST = 'appinfo.json'
12
12
MANIFEST_KINDS = [PACKAGE_MANIFEST , APPINFO_MANIFEST ]
@@ -33,57 +33,39 @@ def path(self):
33
33
return None
34
34
35
35
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 )
44
39
45
40
46
41
def find_project_root_and_manifest (project_items ):
47
42
""" Given the contents of an archive, find a valid Pebble project.
48
43
:param project_items: A list of BaseProjectItems
49
44
:return: A tuple of (path_to_project, manifest BaseProjectItem)
50
45
"""
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_directories = set ()
71
48
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 ))
87
56
continue
88
- return base_dir , manifest_item
57
+
58
+ # Otherwise, check if the file is a source file
59
+ if item_path .endswith (('.c' , '.js' )):
60
+ # If it is a source file in an 'src' directory, add its parent to the set of potential project directories
61
+ source_dir_dirname , source_dir_basename = os .path .split (item_dirname )
62
+ if source_dir_basename == SRC_DIR :
63
+ found_src_directories .add (source_dir_dirname )
64
+
65
+ # Choose the most shallow manifest file which has a non-empty source directory.
66
+ sorted_manifests = sorted (found_manifests , key = lambda x : rank_manifest_path (* x [0 ]))
67
+ for (base , kind ), item in sorted_manifests :
68
+ if base in found_src_directories :
69
+ base = base + os .sep if base else ""
70
+ return base + os .sep , item
89
71
raise InvalidProjectArchiveException (_ ("No project root found." ))
0 commit comments