@@ -48,6 +48,71 @@ import { IInjector } from "../common/definitions/yok";
48
48
import { injector } from "../common/yok" ;
49
49
import { INotConfiguredEnvOptions } from "../common/definitions/commands" ;
50
50
51
+ interface NativeDependency {
52
+ name : string ;
53
+ directory : string ;
54
+ dependencies : string [ ] ;
55
+ }
56
+
57
+ //
58
+ // we sort the native dependencies topologically to make sure they are processed in the right order
59
+ // native dependenciess need to be sorted so the deepst dependencies are built before it's parents
60
+ //
61
+ // for example, given this dep structure (assuming these are all native dependencies that need to be built)
62
+ // |- dep1
63
+ // |- dep2
64
+ // |- dep3
65
+ // |- dep4
66
+ // |-dep5
67
+ // |- dep6
68
+ //
69
+ // It is sorted:
70
+ // |- dep1 - doesn't depend on anything, so the order stays the same as in the input list
71
+ // |- dep3 - doesn't depend on anything, so the order stays the same as in the input list
72
+ // |- dep5 - doesn't depend on anything, so the order stays the same as in the input list
73
+ // |- dep6 - doesn't depend on anything, so the order stays the same as in the input list
74
+ // |- dep4 - depends on dep6, so dep6 must be built first, ie above ^
75
+ // |- dep2 - depends on dep3, dep4, dep5 and dep6, so all of them must be built first
76
+ //
77
+ // for more details see: https://wikiless.org/wiki/Topological_sorting?lang=en
78
+ //
79
+ function topologicalSortNativeDependencies (
80
+ nativeDeps : NativeDependency [ ] ,
81
+ start : NativeDependency [ ] = [ ] ,
82
+ depth = 0
83
+ ) : NativeDependency [ ] {
84
+ const processedDeps = nativeDeps . reduce (
85
+ ( accumulator , nativeDep : NativeDependency ) => {
86
+ if (
87
+ nativeDep . dependencies . every (
88
+ Array . prototype . includes ,
89
+ accumulator . map ( ( n ) => n . name )
90
+ )
91
+ ) {
92
+ accumulator . push ( nativeDep ) ;
93
+ }
94
+ return accumulator ;
95
+ } ,
96
+ start
97
+ ) ;
98
+
99
+ const remainingDeps = nativeDeps . filter (
100
+ ( nativeDep ) => ! processedDeps . includes ( nativeDep )
101
+ ) ;
102
+
103
+ // recurse if we still have unprocessed deps
104
+ // the second condition here prevents infinite recursion
105
+ if ( remainingDeps . length && depth <= nativeDeps . length ) {
106
+ return topologicalSortNativeDependencies (
107
+ remainingDeps ,
108
+ processedDeps ,
109
+ depth + 1
110
+ ) ;
111
+ }
112
+
113
+ return processedDeps ;
114
+ }
115
+
51
116
export class AndroidProjectService extends projectServiceBaseLib . PlatformProjectServiceBase {
52
117
private static VALUES_DIRNAME = "values" ;
53
118
private static VALUES_VERSION_DIRNAME_PREFIX =
@@ -635,10 +700,10 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
635
700
public async beforePrepareAllPlugins (
636
701
projectData : IProjectData ,
637
702
dependencies ?: IDependencyData [ ]
638
- ) : Promise < void > {
703
+ ) : Promise < IDependencyData [ ] > {
639
704
if ( dependencies ) {
640
705
dependencies = this . filterUniqueDependencies ( dependencies ) ;
641
- this . provideDependenciesJson ( projectData , dependencies ) ;
706
+ return this . provideDependenciesJson ( projectData , dependencies ) ;
642
707
}
643
708
}
644
709
@@ -666,7 +731,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
666
731
private provideDependenciesJson (
667
732
projectData : IProjectData ,
668
733
dependencies : IDependencyData [ ]
669
- ) : void {
734
+ ) : IDependencyData [ ] {
670
735
const platformDir = path . join (
671
736
projectData . platformsDir ,
672
737
AndroidProjectService . ANDROID_PLATFORM_NAME
@@ -675,15 +740,37 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
675
740
platformDir ,
676
741
constants . DEPENDENCIES_JSON_NAME
677
742
) ;
678
- const nativeDependencies = dependencies
679
- . filter ( AndroidProjectService . isNativeAndroidDependency )
680
- . map ( ( { name, directory } ) => ( {
681
- name,
682
- directory : path . relative ( platformDir , directory ) ,
683
- } ) ) ;
684
- const jsonContent = JSON . stringify ( nativeDependencies , null , 4 ) ;
743
+ let nativeDependencyData = dependencies . filter (
744
+ AndroidProjectService . isNativeAndroidDependency
745
+ ) ;
685
746
747
+ let nativeDependencies = nativeDependencyData . map (
748
+ ( { name, directory, dependencies } ) => {
749
+ return {
750
+ name,
751
+ directory : path . relative ( platformDir , directory ) ,
752
+ dependencies : dependencies . filter ( ( dep ) => {
753
+ // filter out transient dependencies that don't have native dependencies
754
+ return (
755
+ nativeDependencyData . findIndex (
756
+ ( nativeDep ) => nativeDep . name === dep
757
+ ) !== - 1
758
+ ) ;
759
+ } ) ,
760
+ } as NativeDependency ;
761
+ }
762
+ ) ;
763
+ nativeDependencies = topologicalSortNativeDependencies ( nativeDependencies ) ;
764
+ const jsonContent = JSON . stringify ( nativeDependencies , null , 4 ) ;
686
765
this . $fs . writeFile ( dependenciesJsonPath , jsonContent ) ;
766
+
767
+ // we sort all the dependencies to respect the topological sorting of the native dependencies
768
+ return dependencies . sort ( function ( a , b ) {
769
+ return (
770
+ nativeDependencies . findIndex ( ( n ) => n . name === a . name ) -
771
+ nativeDependencies . findIndex ( ( n ) => n . name === b . name )
772
+ ) ;
773
+ } ) ;
687
774
}
688
775
689
776
private static isNativeAndroidDependency ( {
0 commit comments