Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add optional --fix-content-type TDE-859 #655

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ LINZ uses [Argo workflows](https://argoproj.github.io/workflows/) for running bu
- [create-manifest](#create-manifest)
- [group](#group)
- [list](#list)
- [pretty-print](#pretty-print)
- [format-json](#format-json)
- [stac catalog](#stac-catalog)
- [stac github-import](#stac-github-import)
- [stac sync](#stac-sync)
Expand Down Expand Up @@ -68,22 +68,22 @@ list s3://linz-imagery/sample --include ".*.tiff$" --group 10 --group-size 100MB
list s3://linz-imagery/sample --include ".*.tiff$" --exclude "BG33.tiff$" --output /tmp/list.json
```

### `pretty-print`
### `format-json`

Format all JSON files within a directory using `prettier`.
Format all JSON files within a directory using `prettier`. An optional flag `--fix-content-type` allows to set the content-type for s3 object with a value depending on the STAC object type.

#### Example

- Format and overwrite files:

```bash
pretty-print source/
format-json source/ [--fix-content-type]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How come the name change? prettier will format a lot more than json. eg markdown, yaml, javascript etc..

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it's looking for json files atm. I can make the function more generic and look at other file format but I feel it will need a bit more work, specially around the --fix-content-type

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a breaking change to rename it, so Id prefer to leave it as is if we can?

```

- Create a copy of the formatted file in another flatten directory (testing only - does not handle duplicate filenames):

```bash
pretty-print source/ --target output/
format-json source/ --target output/
```

### `create-manifest`
Expand Down
2 changes: 1 addition & 1 deletion src/commands/basemaps-github/make.cog.github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { TileSetConfigSchema } from '@basemaps/config/build/json/parse.tile.set.
import { fsa, LogType } from '@basemaps/shared';

import { DEFAULT_PRETTIER_FORMAT } from '../../utils/config.js';
import { prettyPrint } from '../format/pretty.print.js';
import { prettyPrint } from '../format/format.json.js';
import { createPR, GithubApi } from './github.js';

export enum Category {
Expand Down
17 changes: 17 additions & 0 deletions src/commands/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,20 @@ export function parseSize(size: string): number {
if (isNaN(fileSize)) throw new Error(`Failed to parse: ${size} as a file size`);
return Math.round(fileSize);
}

/**
* Guess the content type of a STAC file
*
* - application/geo+json - A STAC Item
* - application/json - A STAC Catalog
* - application/json - A STAC Collection
*
* Assumes anything ending with '.json' is a stac item
* @see {@link https://github.com/radiantearth/stac-spec/blob/master/catalog-spec/catalog-spec.md#stac-media-types}
*/
export function guessStacContentType(path: string): string | undefined {
if (path.endsWith('collection.json')) return 'application/json';
if (path.endsWith('catalog.json')) return 'application/json';
if (path.endsWith('.json')) return 'application/geo+json';
return;
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import { fsa } from '@chunkd/fs';
import { command, option, optional, positional, string } from 'cmd-ts';
import { boolean, command, flag, option, optional, positional, string } from 'cmd-ts';
import { basename } from 'path';
import prettier from 'prettier';

import { CliInfo } from '../../cli.info.js';
import { logger } from '../../log.js';
import { getFiles } from '../../utils/chunk.js';
import { DEFAULT_PRETTIER_FORMAT } from '../../utils/config.js';
import { config, registerCli, verbose } from '../common.js';
import { config, guessStacContentType, registerCli, verbose } from '../common.js';

function isJson(x: string): boolean {
const search = x.toLowerCase();
return search.endsWith('.json');
}

export const commandPrettyPrint = command({
name: 'pretty-print',
description: 'Pretty print JSON files',
export const commandFormatJson = command({
name: 'format-jspon',
paulfouquet marked this conversation as resolved.
Show resolved Hide resolved
description: 'Format JSON files',
version: CliInfo.version,
args: {
config,
Expand All @@ -26,15 +26,22 @@ export const commandPrettyPrint = command({
long: 'target',
description: 'Use if files have to be saved somewhere else instead of overwriting the source (testing)',
}),
fixContentType: flag({
type: boolean,
defaultValue: () => false,
long: 'fix-content-type',
description: 'Append a guessed content-type to the S3 object.',
defaultValueIsSerializable: true,
}),
path: positional({ type: string, displayName: 'path', description: 'Path of the files to pretty print' }),
},

async handler(args) {
registerCli(this, args);
const startTime = performance.now();
logger.info('PrettyPrint:Start');
logger.info('FormatJson:Start');
if (args.target) {
logger.info({ target: args.target }, 'PrettyPrint:Info');
logger.info({ target: args.target }, 'FormatJson:Info');
}

const files = await getFiles([args.path]);
Expand All @@ -45,8 +52,8 @@ export const commandPrettyPrint = command({
if (jsonFiles[0]) await fsa.head(jsonFiles[0]);

// format files
await Promise.all(jsonFiles.map((f: string) => formatFile(f, args.target)));
logger.info({ fileCount: jsonFiles.length, duration: performance.now() - startTime }, 'PrettyPrint:Done');
await Promise.all(jsonFiles.map((f: string) => formatFile(f, args.target, args.fixContentType)));
logger.info({ fileCount: jsonFiles.length, duration: performance.now() - startTime }, 'FormatJson:Done');
},
});

Expand All @@ -55,16 +62,19 @@ export const commandPrettyPrint = command({
*
* @param path of the file to format
* @param target where to save the output. If not specified, overwrite the original file.
* @param fixContentType if true will set the `contentType` with a guessed value. @see guessStacContentType
*/
export async function formatFile(path: string, target = ''): Promise<void> {
logger.debug({ file: path }, 'PrettyPrint:RunPrettier');
export async function formatFile(path: string, target = '', fixContentType: boolean = false): Promise<void> {
logger.debug({ file: path }, 'FormatJson:RunPrettier');
const prettyPrinted = await prettyPrint(JSON.stringify(await fsa.readJson(path)), DEFAULT_PRETTIER_FORMAT);
if (target) {
// FIXME: can be duplicate files
path = fsa.join(target, basename(path));
}
let meta = {};
if (fixContentType) meta = { contentType: guessStacContentType(path) };

fsa.write(path, Buffer.from(prettyPrinted));
fsa.write(path, Buffer.from(prettyPrinted), meta);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { CliInfo } from '../cli.info.js';
import { basemapsCreatePullRequest } from './basemaps-github/create-pr.js';
import { commandCopy } from './copy/copy.js';
import { commandCreateManifest } from './create-manifest/create-manifest.js';
import { commandPrettyPrint } from './format/pretty.print.js';
import { commandFormatJson } from './format/format.json.js';
import { commandGroup } from './group/group.js';
import { commandLdsFetch } from './lds-cache/lds.cache.js';
import { commandList } from './list/list.js';
Expand Down Expand Up @@ -46,6 +46,6 @@ export const cmd = subcommands({
'create-pr': basemapsCreatePullRequest,
},
}),
'pretty-print': commandPrettyPrint,
'format-json': commandFormatJson,
},
});
2 changes: 1 addition & 1 deletion src/commands/stac-github-import/stac.github.import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import * as st from 'stac-ts';
import { CliInfo } from '../../cli.info.js';
import { logger } from '../../log.js';
import { config, registerCli, verbose } from '../common.js';
import { formatFile } from '../format/pretty.print.js';
import { formatFile } from '../format/format.json.js';

const Url: Type<string, URL> = {
async from(str) {
Expand Down
19 changes: 1 addition & 18 deletions src/commands/stac-sync/stac.sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { createHash } from 'crypto';

import { CliInfo } from '../../cli.info.js';
import { logger } from '../../log.js';
import { config, registerCli, verbose } from '../common.js';
import { config, guessStacContentType, registerCli, verbose } from '../common.js';

const S3Path: Type<string, URL> = {
async from(str) {
Expand Down Expand Up @@ -85,20 +85,3 @@ export async function uploadFileToS3(sourceFileInfo: FileInfo, path: URL): Promi
logger.debug({ path: path.href }, 'StacSync:FileUploaded');
return true;
}

/**
* Guess the content type of a STAC file
*
* - application/geo+json - A STAC Item
* - application/json - A STAC Catalog
* - application/json - A STAC Collection
*
* Assumes anything ending with '.json' is a stac item
* @see {@link https://github.com/radiantearth/stac-spec/blob/master/catalog-spec/catalog-spec.md#stac-media-types}
*/
function guessStacContentType(path: string): string | undefined {
if (path.endsWith('collection.json')) return 'application/json';
if (path.endsWith('catalog.json')) return 'application/json';
if (path.endsWith('.json')) return 'application/geo+json';
return;
}