Skip to content

Commit

Permalink
fix(app): accept mixed-case extensions for protocols and custom labwa…
Browse files Browse the repository at this point in the history
…re (#5153)

Closes #5151
  • Loading branch information
mcous authored Mar 3, 2020
1 parent 69f82f3 commit 12cce54
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 11 deletions.
18 changes: 17 additions & 1 deletion app-shell/src/labware/__tests__/definitions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe('labware directory utilities', () => {
).rejects.toThrow(/no such file/)
})

test('returns paths to JSON files in directory', () => {
test('returns paths to *.json files in directory', () => {
const dir = makeEmptyDir()

return Promise.all([
Expand Down Expand Up @@ -76,6 +76,22 @@ describe('labware directory utilities', () => {
])
})
})

test('returns paths to *.JSON files in directory', () => {
const dir = makeEmptyDir()

return Promise.all([
fs.writeJson(path.join(dir, 'a.JSON'), { name: 'a' }),
fs.writeJson(path.join(dir, 'b.JSON'), { name: 'b' }),
fs.writeJson(path.join(dir, 'c.JSON'), { name: 'c' }),
]).then(() => {
return expect(readLabwareDirectory(dir)).resolves.toEqual([
path.join(dir, 'a.JSON'),
path.join(dir, 'b.JSON'),
path.join(dir, 'c.JSON'),
])
})
})
})

describe('parseLabwareFiles', () => {
Expand Down
4 changes: 3 additions & 1 deletion app-shell/src/labware/definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ import { shell } from 'electron'
import type { Dirent } from '../types'
import type { UncheckedLabwareFile } from '@opentrons/app/src/custom-labware/types'

const RE_JSON_EXT = /\.json$/i

export function readLabwareDirectory(dir: string): Promise<Array<string>> {
const absoluteName = e => path.join(dir, e.name)

return fs
.readdir(dir, { withFileTypes: true })
.then((entries: Array<Dirent>) => {
const jsonFiles = entries
.filter(e => e.isFile() && e.name.endsWith('.json'))
.filter(e => e.isFile() && RE_JSON_EXT.test(e.name))
.map(absoluteName)

const getNestedFiles = Promise.all(
Expand Down
42 changes: 40 additions & 2 deletions app/src/protocol/__tests__/reducer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ describe('protocolReducer', () => {
},
},
{
name: 'handles robot:SESSION_RESPONSE with JSON protocol',
name: 'handles robot:SESSION_RESPONSE with .json protocol',
action: {
type: 'robot:SESSION_RESPONSE',
payload: { name: 'foo.json', protocolText: '{"metadata": {}}' },
Expand All @@ -61,7 +61,7 @@ describe('protocolReducer', () => {
},
},
{
name: 'handles robot:SESSION_RESPONSE with Python protocol metadata',
name: 'handles robot:SESSION_RESPONSE with .py protocol',
action: {
type: 'robot:SESSION_RESPONSE',
payload: {
Expand All @@ -81,6 +81,44 @@ describe('protocolReducer', () => {
data: { metadata: { protocolName: 'foo' } },
},
},
{
name: 'handles robot:SESSION_RESPONSE with .JSON protocol',
action: {
type: 'robot:SESSION_RESPONSE',
payload: { name: 'foo.JSON', protocolText: '{"metadata": {}}' },
},
initialState: { file: null, contents: null, data: null },
expectedState: {
file: {
name: 'foo.JSON',
type: 'json',
lastModified: null,
},
contents: '{"metadata": {}}',
data: { metadata: {} },
},
},
{
name: 'handles robot:SESSION_RESPONSE with .PY protocol',
action: {
type: 'robot:SESSION_RESPONSE',
payload: {
name: 'foo.PY',
protocolText: '# foo.py',
metadata: { protocolName: 'foo' },
},
},
initialState: { file: null, contents: null, data: null },
expectedState: {
file: {
name: 'foo.PY',
type: 'python',
lastModified: null,
},
contents: '# foo.py',
data: { metadata: { protocolName: 'foo' } },
},
},
{
name: 'handles robot:DISCONNECT by clearing state',
action: { type: 'robot:DISCONNECT_RESPONSE' },
Expand Down
6 changes: 6 additions & 0 deletions app/src/protocol/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// @flow

// protocol types
export const TYPE_JSON: 'json' = 'json'
export const TYPE_PYTHON: 'python' = 'python'
export const TYPE_ZIP: 'zip' = 'zip'
1 change: 1 addition & 0 deletions app/src/protocol/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type {
InvalidProtocolFileAction,
} from './types'

export * from './constants'
export * from './selectors'

const BUNDLE_UPLOAD_DISABLED =
Expand Down
17 changes: 11 additions & 6 deletions app/src/protocol/protocol-data.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
// @flow
// functions for parsing protocol files
import { createLogger } from '../logger'
import { TYPE_JSON, TYPE_PYTHON, TYPE_ZIP } from './constants'

import type { ProtocolFile, ProtocolData, ProtocolType } from './types'

const log = createLogger(__filename)

const RE_JSON_EXT = /\.json$/i
const RE_PY_EXT = /\.py$/i
const RE_ZIP_EXT = /\.zip$/i

export function filenameToType(filename: string): ProtocolType | null {
if (filename.endsWith('.json')) return 'json'
if (filename.endsWith('.py')) return 'python'
if (filename.endsWith('.zip')) return 'zip'
if (RE_JSON_EXT.test(filename)) return TYPE_JSON
if (RE_PY_EXT.test(filename)) return TYPE_PYTHON
if (RE_ZIP_EXT.test(filename)) return TYPE_ZIP
return null
}

Expand Down Expand Up @@ -44,15 +49,15 @@ export function parseProtocolData(
}

export function fileIsPython(file: ProtocolFile): boolean {
return file.type === 'python' || file.type == null
return file.type === TYPE_PYTHON || file.type == null
}

export function fileIsJson(file: ProtocolFile): boolean {
return file.type === 'json'
return file.type === TYPE_JSON
}

export function fileIsBundle(file: ProtocolFile): boolean {
return file.type === 'zip'
return file.type === TYPE_ZIP
}

export function fileIsBinary(file: ProtocolFile): boolean {
Expand Down
4 changes: 3 additions & 1 deletion app/src/protocol/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
import type { ProtocolFile as SchemaV1ProtocolFile } from '@opentrons/shared-data/protocol/flowTypes/schemaV1'
import type { ProtocolFile as SchemaV3ProtocolFile } from '@opentrons/shared-data/protocol/flowTypes/schemaV3'

import typeof { TYPE_JSON, TYPE_PYTHON, TYPE_ZIP } from './constants'

// data may be a full JSON protocol or just a metadata dict from Python
export type ProtocolData =
| SchemaV1ProtocolFile<{}>
| SchemaV3ProtocolFile<{}>
| { metadata: $PropertyType<SchemaV1ProtocolFile<{}>, 'metadata'> }
// NOTE: add union of additional versions after schema is bumped

export type ProtocolType = 'json' | 'python' | 'zip'
export type ProtocolType = TYPE_JSON | TYPE_PYTHON | TYPE_ZIP

export type ProtocolFile = {
name: string,
Expand Down

0 comments on commit 12cce54

Please sign in to comment.