11import { MetadataGroup } from '@ionic/cli-framework' ;
2+ import { LOGGER_LEVELS } from '@ionic/cli-framework-output' ;
23import { map } from '@ionic/utils-array' ;
3- import { readdirp , stat , writeFile } from '@ionic/utils-fs' ;
4+ import { pathExists , readdirp , stat , writeFile } from '@ionic/utils-fs' ;
45import { prettyPath } from '@ionic/utils-terminal' ;
56import * as crypto from 'crypto' ;
67import * as fs from 'fs' ;
8+ import lodash = require( 'lodash' ) ;
79import * as path from 'path' ;
10+ import * as Debug from 'debug' ;
811
912import { CommandMetadata } from '../../definitions' ;
1013import { input } from '../../lib/color' ;
1114import { FatalException } from '../../lib/errors' ;
15+ import { prependNodeModulesBinToPath , Shell } from '../../lib/shell' ;
16+ import { createDefaultLoggerHandlers , Logger } from '../../lib/utils/logger' ;
1217
18+ import { CapacitorCLIConfig , CapacitorConfig , CapacitorJSONConfig } from './capacitor' ;
1319import { DeployCoreCommand } from './core' ;
1420
21+ const debug = Debug ( 'ionic:commands:deploy:manifest' ) ;
22+ const CAPACITOR_CONFIG_JSON_FILE = 'capacitor.config.json' ;
23+
1524interface DeployManifestItem {
1625 href : string ;
1726 size : number ;
@@ -20,21 +29,29 @@ interface DeployManifestItem {
2029
2130export class DeployManifestCommand extends DeployCoreCommand {
2231 async getMetadata ( ) : Promise < CommandMetadata > {
32+ // This command is set as type 'global' in order to support Capacitor apps without an ionic.config.json
2333 return {
2434 name : 'manifest' ,
25- type : 'project ' ,
35+ type : 'global ' ,
2636 summary : 'Generates a manifest file for the deploy service from a built app directory' ,
2737 groups : [ MetadataGroup . PAID ] ,
2838 } ;
2939 }
3040
3141 async run ( ) : Promise < void > {
32- if ( ! this . project ) {
42+ const capacitorConfig = await this . getCapacitorConfig ( ) ;
43+ if ( ! this . project && ! capacitorConfig ) {
3344 throw new FatalException ( `Cannot run ${ input ( 'ionic deploy manifest' ) } outside a project directory.` ) ;
3445 }
35- await this . requireNativeIntegration ( ) ;
3646
37- const buildDir = await this . project . getDistDir ( ) ;
47+ let buildDir : string ;
48+ if ( this . project ) {
49+ await this . requireNativeIntegration ( ) ;
50+ buildDir = await this . project . getDistDir ( ) ;
51+ } else {
52+ buildDir = capacitorConfig ! . webDir ? capacitorConfig ! . webDir : 'www' ;
53+ }
54+
3855 const manifest = await this . getFilesAndSizesAndHashesForGlobPattern ( buildDir ) ;
3956
4057 const manifestPath = path . resolve ( buildDir , 'pro-manifest.json' ) ;
@@ -83,4 +100,55 @@ export class DeployManifestCommand extends DeployCoreCommand {
83100 } )
84101 . join ( ' ' ) ;
85102 }
103+
104+ private getCapacitorConfigJsonPath ( ) : string {
105+ return path . resolve ( this . env . ctx . execPath , CAPACITOR_CONFIG_JSON_FILE ) ;
106+ }
107+
108+ private getCapacitorCLIConfig = lodash . memoize ( async ( ) : Promise < CapacitorCLIConfig | undefined > => {
109+ // I had to create a new shell to force prependNodeModulesBinToPath.
110+ // If ionic.config.json is not present, then this.env.shell will not implement this, and the Capacitor command will fail.
111+ const args = [ 'config' , '--json' ] ;
112+ const log = new Logger ( {
113+ level : LOGGER_LEVELS . INFO ,
114+ handlers : createDefaultLoggerHandlers ( ) ,
115+ } ) ;
116+ const shell = new Shell ( { log } , { alterPath : p => { return prependNodeModulesBinToPath ( this . env . ctx . execPath , p ) } } ) ;
117+
118+ debug ( 'Getting config with Capacitor CLI: %O' , args ) ;
119+
120+ const output = await shell . cmdinfo ( 'capacitor' , args ) ;
121+
122+ if ( ! output ) {
123+ debug ( 'Could not get config from Capacitor CLI (probably old version)' ) ;
124+ return ;
125+ }
126+
127+ return JSON . parse ( output ) ;
128+ } ) ;
129+
130+ private getCapacitorConfig = lodash . memoize ( async ( ) : Promise < CapacitorConfig | undefined > => {
131+ const cli = await this . getCapacitorCLIConfig ( ) ;
132+
133+ if ( cli ) {
134+ debug ( 'Loaded Capacitor config!' ) ;
135+ return cli . app . extConfig ;
136+ }
137+
138+ // fallback to reading capacitor.config.json if it exists
139+ const confPath = this . getCapacitorConfigJsonPath ( ) ;
140+
141+ if ( ! ( await pathExists ( confPath ) ) ) {
142+ debug ( 'Capacitor config file does not exist at %O' , confPath ) ;
143+ debug ( 'Failed to load Capacitor config' ) ;
144+ return ;
145+ }
146+
147+ const conf = new CapacitorJSONConfig ( confPath ) ;
148+ const extConfig = conf . c ;
149+
150+ debug ( 'Loaded Capacitor config!' ) ;
151+
152+ return extConfig ;
153+ } ) ;
86154}
0 commit comments