1
- import { Epsg , TileMatrixSets } from '@basemaps/geo' ;
2
- import { fsa , LogType , Url } from '@basemaps/shared' ;
1
+ import { TileMatrixSets } from '@basemaps/geo' ;
2
+ import { fsa , isArgo , LogType , Url , UrlArrayJsonFile } from '@basemaps/shared' ;
3
3
import { CliId , CliInfo } from '@basemaps/shared/build/cli/info.js' ;
4
4
import { getLogger , logArguments } from '@basemaps/shared/build/cli/log.js' ;
5
- import { command , option , string } from 'cmd-ts' ;
6
- import { basename } from 'path' ;
5
+ import { command , option , optional , string } from 'cmd-ts' ;
6
+ import { mkdir } from 'fs/promises' ;
7
+ import path , { basename , dirname } from 'path' ;
7
8
import { createGzip } from 'zlib' ;
8
9
9
10
import { createStacFiles } from '../stac.js' ;
10
11
import { toTarIndex } from '../transform/covt.js' ;
11
12
import { toTarTiles } from '../transform/mbtiles.to.ttiles.js' ;
12
13
import { tileJoin } from '../transform/tippecanoe.js' ;
13
14
14
- async function fromFile ( path : URL ) : Promise < string [ ] > {
15
- const toProcess = await fsa . readJson ( path ) ;
16
- const paths : string [ ] = [ ] ;
17
- if ( ! Array . isArray ( toProcess ) ) throw new Error ( `File ${ path . href } is not an array` ) ;
18
- for ( const task of toProcess ) {
19
- if ( typeof task !== 'string' ) throw new Error ( `File ${ path . href } is not an array of strings` ) ;
20
- const sourceFile = new URL ( task ) ;
21
- if ( sourceFile . protocol === 'file:' ) {
22
- paths . push ( sourceFile . pathname ) ;
15
+ async function download ( filePaths : URL [ ] , outputPath : string , logger : LogType ) : Promise < URL [ ] > {
16
+ const paths : URL [ ] = [ ] ;
17
+ for ( const file of filePaths ) {
18
+ if ( file . protocol === 'file:' ) {
19
+ paths . push ( file ) ;
23
20
} else {
24
- const fileName = basename ( sourceFile . pathname ) ;
25
- if ( fileName == null ) throw new Error ( `Unsupported source pathname ${ sourceFile . pathname } ` ) ;
26
- const localFile = `tmp/join/${ fileName } ` ;
27
- const stream = fsa . readStream ( sourceFile ) ;
28
- await fsa . write ( fsa . toUrl ( localFile ) , stream ) ;
21
+ const fileName = basename ( file . pathname ) ;
22
+ if ( fileName == null ) throw new Error ( `Unsupported source pathname ${ file . pathname } ` ) ;
23
+ const localFile = fsa . toUrl ( `${ outputPath } /downloads/${ fileName } ` ) ;
24
+ if ( await fsa . exists ( localFile ) ) {
25
+ logger . info ( { file : file , localFile, fileName } , 'Download:FileExists' ) ;
26
+ } else {
27
+ const stats = await fsa . head ( file ) ;
28
+ logger . info ( { file : file , localFile, fileName, size : stats ?. size } , 'Download:Start' ) ;
29
+ const stream = fsa . readStream ( file ) ;
30
+ await fsa . write ( localFile , stream ) ;
31
+ logger . info ( { file : file , localFile, fileName } , 'Download:End' ) ;
32
+ }
29
33
paths . push ( localFile ) ;
30
34
}
31
35
}
@@ -36,8 +40,8 @@ async function fromFile(path: URL): Promise<string[]> {
36
40
* Upload output file into s3 bucket
37
41
*
38
42
*/
39
- async function upload ( file : URL , bucketPath : string , logger : LogType ) : Promise < URL > {
40
- logger . info ( { file : file } , 'Load:Start' ) ;
43
+ async function upload ( file : URL , bucketPath : URL , logger : LogType ) : Promise < URL > {
44
+ logger . info ( { file : file . href } , 'Load:Start' ) ;
41
45
let filename = basename ( file . pathname ) ;
42
46
let stream = fsa . readStream ( file ) ;
43
47
@@ -47,9 +51,11 @@ async function upload(file: URL, bucketPath: string, logger: LogType): Promise<U
47
51
stream = stream . pipe ( createGzip ( ) ) ;
48
52
}
49
53
50
- // Upload to s3
51
- let path = fsa . toUrl ( `${ bucketPath } /${ CliId } /${ filename } ` ) ;
52
- if ( filename . endsWith ( 'catalog.json' ) ) path = fsa . toUrl ( `${ bucketPath } /${ filename } ` ) ; // Upload catalog to root directory
54
+ // Upload to s3 or copy to local
55
+ let path = new URL ( `topographic/${ CliId } /${ filename } ` , bucketPath ) ;
56
+ logger . info ( { file : file , path : path } , 'Load:Path' ) ;
57
+ if ( path . protocol === 'file:' ) await mkdir ( dirname ( path . pathname ) , { recursive : true } ) ;
58
+ if ( filename . endsWith ( 'catalog.json' ) ) path = new URL ( filename , bucketPath ) ; // Upload catalog to root directory
53
59
await fsa . write ( path , stream ) ;
54
60
logger . info ( { file : file , path : path } , 'Load:Finish' ) ;
55
61
return path ;
@@ -58,7 +64,7 @@ async function upload(file: URL, bucketPath: string, logger: LogType): Promise<U
58
64
export const JoinArgs = {
59
65
...logArguments ,
60
66
fromFile : option ( {
61
- type : Url ,
67
+ type : UrlArrayJsonFile ,
62
68
long : 'from-file' ,
63
69
description : 'Path to JSON file containing array of paths to mbtiles.' ,
64
70
} ) ,
@@ -80,13 +86,13 @@ export const JoinArgs = {
80
86
type : string ,
81
87
long : 'title' ,
82
88
description : 'Title for the output etl data in the STAC file' ,
83
- defaultValue : ( ) => 'Topographic' ,
89
+ defaultValue : ( ) => 'Topographic V2 ' ,
84
90
defaultValueIsSerializable : true ,
85
91
} ) ,
86
92
target : option ( {
87
- type : string ,
93
+ type : optional ( Url ) ,
88
94
long : 'target' ,
89
- description : 'Path of target location, could be local or s3' ,
95
+ description : 'Path of target location to upload the processed file , could be local or s3' ,
90
96
} ) ,
91
97
} ;
92
98
@@ -97,32 +103,49 @@ export const JoinCommand = command({
97
103
args : JoinArgs ,
98
104
async handler ( args ) {
99
105
const logger = getLogger ( this , args , 'cli-vector' ) ;
100
- const filePaths = await fromFile ( args . fromFile ) ;
101
-
102
- logger . info ( { files : filePaths . length } , 'JoinMbtiles: Start' ) ;
103
-
104
- const outputMbtiles = fsa . toUrl ( `tmp/${ args . filename } .mbtiles` ) . pathname ;
106
+ const outputPath = path . resolve ( 'tmp/join/' ) ;
107
+ await mkdir ( outputPath , { recursive : true } ) ;
108
+ const tileMatrix = TileMatrixSets . find ( args . tileMatrix ) ;
109
+ if ( tileMatrix == null ) throw new Error ( `Tile matrix ${ args . tileMatrix } is not supported` ) ;
110
+ const bucketPath = new URL ( `vector/${ tileMatrix . projection . code } /` , args . target ?? outputPath ) ;
111
+ const filePaths = await download ( args . fromFile , outputPath , logger ) ;
105
112
113
+ const outputMbtiles = path . join ( outputPath , `${ args . filename } .mbtiles` ) ;
114
+ logger . info ( { files : filePaths . length , outputMbtiles } , 'JoinMbtiles: Start' ) ;
106
115
await tileJoin ( filePaths , outputMbtiles , logger ) ;
116
+ logger . info ( { files : filePaths . length , outputMbtiles } , 'JoinMbtiles: End' ) ;
107
117
108
- const outputCotar = fsa . toUrl ( `tmp/ ${ args . filename } .covt `) ;
109
-
118
+ const outputCotar = path . join ( outputPath , ` ${ args . filename } .tar.co `) ;
119
+ logger . info ( { mbtiles : outputMbtiles , outputCotar } , 'ToTartTiles: Start' ) ;
110
120
await toTarTiles ( outputMbtiles , outputCotar , logger ) ;
121
+ logger . info ( { mbtiles : outputMbtiles , outputCotar } , 'ToTartTiles: End' ) ;
111
122
112
- const [ outputIndex , outputTar ] = await toTarIndex ( outputCotar , 'tmp/' , args . filename , logger ) ;
123
+ const outputIndex = path . join ( outputPath , `${ args . filename } .tar.index` ) ;
124
+ logger . info ( { cotar : outputCotar , outputIndex } , 'toTarIndex: Start' ) ;
125
+ await toTarIndex ( outputCotar , outputIndex , logger ) ;
126
+ logger . info ( { cotar : outputCotar , outputIndex } , 'toTarIndex: End' ) ;
113
127
114
- const tileMatrix = TileMatrixSets . find ( args . tileMatrix ) ;
115
- if ( tileMatrix == null ) throw new Error ( `Tile matrix ${ args . tileMatrix } is not supported` ) ;
116
- const stacFiles = await createStacFiles ( filePaths , args . target , args . filename , tileMatrix , args . title , logger ) ;
128
+ logger . info ( { target : bucketPath , tileMatrix : tileMatrix . identifier } , 'CreateStac: Start' ) ;
129
+ const stacFiles = await createStacFiles ( args . fromFile , bucketPath , args . filename , tileMatrix , args . title , logger ) ;
130
+ logger . info ( { cotar : outputCotar , outputIndex } , 'CreateStac: End' ) ;
117
131
118
132
// Upload output to s3
119
- const bucketPath = `${ args . target } /vector/${ Epsg . Google . code . toString ( ) } /${ args . filename } ` ;
120
- await upload ( fsa . toUrl ( outputMbtiles ) , bucketPath , logger ) ;
121
- await upload ( fsa . toUrl ( outputTar ) , bucketPath , logger ) ;
122
- await upload ( fsa . toUrl ( outputIndex ) , bucketPath , logger ) ;
123
- // Upload stac Files
124
- for ( const file of stacFiles ) {
125
- await upload ( file , bucketPath , logger ) ;
133
+ logger . info ( { target : bucketPath , tileMatrix : tileMatrix . identifier } , 'Upload: Start' ) ;
134
+ if ( args . target ) {
135
+ await upload ( fsa . toUrl ( outputMbtiles ) , bucketPath , logger ) ;
136
+ await upload ( fsa . toUrl ( outputCotar ) , bucketPath , logger ) ;
137
+ await upload ( fsa . toUrl ( outputIndex ) , bucketPath , logger ) ;
138
+ // Upload stac Files
139
+ for ( const file of stacFiles ) {
140
+ await upload ( file , bucketPath , logger ) ;
141
+ }
142
+ logger . info ( { target : bucketPath , tileMatrix : tileMatrix . identifier } , 'Upload: End' ) ;
143
+ }
144
+
145
+ // Write output target for argo tasks to create pull request
146
+ if ( isArgo ( ) ) {
147
+ const target = new URL ( `topographic/${ CliId } /${ args . filename } .tar.co` , bucketPath ) ;
148
+ await fsa . write ( fsa . toUrl ( '/tmp/target' ) , JSON . stringify ( [ target ] ) ) ;
126
149
}
127
150
} ,
128
151
} ) ;
0 commit comments