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

Feature/ir migration #1034

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
48 changes: 48 additions & 0 deletions ir-migration/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import * as fs from "fs";
import * as util from "util";
import * as path from "path";
import * as v1 from "./migrations/v1Migration";
import * as v2 from "./migrations/v2Migration";
import * as v3 from "./migrations/v3Migration";

const fsReadFile = util.promisify(fs.readFile);

type Json = object;

type Migration = (previousVersion: Json) => Json;

const MigrationList: Migration[] = [
v1.Migration,
v2.Migration,
v3.Migration
];

/**
* This function loads the Morphir-ir-json from path supplied, checks if the version is update to date, and if not upgrades the IR automically.
*
* @param projectDir
* @param migrationList
* @returns Promise<Json>
*/
async function migrate(projectDir: string, migrationList: any): Promise<Json> {
const morphirIrPath: string = path.join(projectDir, "morphir-ir.json");
const morphirIRJSON = JSON.parse(
(await fsReadFile(morphirIrPath)).toString()
);
const loadedIRVersion = morphirIRJSON["formatVersion"];

if (loadedIRVersion != migrationList.length) {
let versionedIRJSON: Json = morphirIRJSON;
for (let i = loadedIRVersion; i < migrationList.length; i++) {
let nextMigrationtoRun = i - 1; // considering the 0 index of a List
let migration = migrationList[nextMigrationtoRun];
versionedIRJSON = migration(morphirIRJSON);
}
return versionedIRJSON;
} else {
// do nothing. IR is latest
return morphirIRJSON;
}
}

export { migrate, MigrationList, Json };
14 changes: 14 additions & 0 deletions ir-migration/src/migrations/v1Migration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Json } from "../../src/main";

export function Migration(iRJSON: Json): Json {
console.log("Migrating From v1 to v2");

// migration logic

let finalIRJSON = {
formatVersion: iRJSON["formatVersion"] + 1,
distribution: [],
};

return finalIRJSON;
}
14 changes: 14 additions & 0 deletions ir-migration/src/migrations/v2Migration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Json } from "../../src/main";

export function Migration(iRJSON: Json): Json {
console.log("Migrating From v2 to v3");

// migration logic

let finalIRJSON = {
formatVersion: iRJSON["formatVersion"] + 1,
distribution: [],
};

return finalIRJSON;
}
14 changes: 14 additions & 0 deletions ir-migration/src/migrations/v3Migration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Json } from "../../src/main";

export function Migration(iRJSON: Json): Json {
console.log("Migrating From v3 to v4");

// migration logic

let finalIRJSON = {
formatVersion: iRJSON["formatVersion"] + 1,
distribution: [],
};

return finalIRJSON;
}
33 changes: 3 additions & 30 deletions src/Morphir/IR/Distribution/Codec.elm
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,18 @@ import Json.Encode as Encode
import Morphir.Codec exposing (decodeUnit, encodeUnit)
import Morphir.IR.Distribution exposing (Distribution(..))
import Morphir.IR.Distribution.CodecV1 as CodecV1
import Morphir.IR.Distribution.CodecV2 as CodecV2
import Morphir.IR.Package.Codec as PackageCodec
import Morphir.IR.Path.Codec exposing (decodePath, encodePath)
import Morphir.IR.Type.Codec exposing (decodeType, encodeType)


{-| This is a manually managed version number to be able to handle breaking changes in the IR format more explicitly.
-}
currentFormatVersion : Int
currentFormatVersion =
2


{-| Encode distribution including a version number.
-}
encodeVersionedDistribution : Distribution -> Encode.Value
encodeVersionedDistribution distro =
Encode.object
[ ( "formatVersion", Encode.int currentFormatVersion )
, ( "distribution", encodeDistribution distro )
[ ( "distribution", encodeDistribution distro )
]


Expand All @@ -59,27 +52,7 @@ encodeVersionedDistribution distro =
decodeVersionedDistribution : Decode.Decoder Distribution
decodeVersionedDistribution =
Decode.oneOf
[ Decode.field "formatVersion" Decode.int
|> Decode.andThen
(\formatVersion ->
if formatVersion == currentFormatVersion then
Decode.field "distribution" decodeDistribution

else if formatVersion == 1 then
Decode.field "distribution" CodecV1.decodeDistribution

else
Decode.fail
(String.concat
[ "The IR is using format version "
, String.fromInt formatVersion
, " but the latest format version is "
, String.fromInt currentFormatVersion
, ". Please regenerate it!"
]
)
)
, Decode.fail "The IR is in an old format that doesn't have a format version on it. Please regenerate it!"
[ Decode.field "distribution" decodeDistribution
]


Expand Down
135 changes: 135 additions & 0 deletions src/Morphir/IR/Distribution/CodecV2.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
{-
Copyright 2020 Morgan Stanley

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-}


module Morphir.IR.Distribution.CodecV2 exposing (encodeVersionedDistribution, decodeVersionedDistribution, encodeDistribution, decodeDistribution)

{-| Codecs for types in the `Morphir.IR.Distribution` module.


# Distribution

@docs encodeVersionedDistribution, decodeVersionedDistribution, encodeDistribution, decodeDistribution

-}

import Dict
import Json.Decode as Decode
import Json.Encode as Encode
import Morphir.Codec exposing (decodeUnit, encodeUnit)
import Morphir.IR.Distribution exposing (Distribution(..))
import Morphir.IR.Distribution.CodecV1 as CodecV1
import Morphir.IR.Package.Codec as PackageCodec
import Morphir.IR.Path.Codec exposing (decodePath, encodePath)
import Morphir.IR.Type.Codec exposing (decodeType, encodeType)


{-| This is a manually managed version number to be able to handle breaking changes in the IR format more explicitly.
-}
currentFormatVersion : Int
currentFormatVersion =
2


{-| Encode distribution including a version number.
-}
encodeVersionedDistribution : Distribution -> Encode.Value
encodeVersionedDistribution distro =
Encode.object
[ ( "formatVersion", Encode.int currentFormatVersion )
, ( "distribution", encodeDistribution distro )
]


{-| Decode distribution including a version number.
-}
decodeVersionedDistribution : Decode.Decoder Distribution
decodeVersionedDistribution =
Decode.oneOf
[ Decode.field "formatVersion" Decode.int
|> Decode.andThen
(\formatVersion ->
if formatVersion == currentFormatVersion then
Decode.field "distribution" decodeDistribution

else if formatVersion == 1 then
Decode.field "distribution" CodecV1.decodeDistribution

else
Decode.fail
(String.concat
[ "The IR is using format version "
, String.fromInt formatVersion
, " but the latest format version is "
, String.fromInt currentFormatVersion
, ". Please regenerate it!"
]
)
)
, Decode.fail "The IR is in an old format that doesn't have a format version on it. Please regenerate it!"
]


{-| Encode Distribution.
-}
encodeDistribution : Distribution -> Encode.Value
encodeDistribution distro =
case distro of
Library packagePath dependencies def ->
Encode.list identity
[ Encode.string "Library"
, encodePath packagePath
, dependencies
|> Dict.toList
|> Encode.list
(\( packageName, packageSpec ) ->
Encode.list identity
[ encodePath packageName
, PackageCodec.encodeSpecification encodeUnit packageSpec
]
)
, def
|> PackageCodec.encodeDefinition encodeUnit
(encodeType encodeUnit)
]


{-| Decode Distribution.
-}
decodeDistribution : Decode.Decoder Distribution
decodeDistribution =
Decode.index 0 Decode.string
|> Decode.andThen
(\kind ->
case kind of
"Library" ->
Decode.map3 Library
(Decode.index 1 decodePath)
(Decode.index 2
(Decode.map Dict.fromList
(Decode.list
(Decode.map2 Tuple.pair
(Decode.index 0 decodePath)
(Decode.index 1 (PackageCodec.decodeSpecification decodeUnit))
)
)
)
)
(Decode.index 3 (PackageCodec.decodeDefinition decodeUnit (decodeType decodeUnit)))

other ->
Decode.fail <| "Unknown value type: " ++ other
)
Loading