diff --git a/models/i18n.go b/models/i18n.go index d034c22..395798e 100644 --- a/models/i18n.go +++ b/models/i18n.go @@ -1,150 +1,158 @@ /* Copyright © 2017 Harald Sitter This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package models import ( "encoding/json" "strings" ) // I18nInputData is an auxiliary struct used to unmarshal the input data from // disk which uses snake_case in its json representation. This struct should // not be used directly, it is used by UnmarshalJSON whilst working with // a I18nData. I18nData's UnmarshalJSON should be kept in sync with // new fields here! type i18nInputData struct { Stable string `json:"stable"` StableKF5 string `json:"stable_kf5"` Trunk string `json:"trunk"` TrunkKF5 string `json:"trunk_kf5"` } // I18nData represents I18n relevant data. type I18nData struct { Stable string `json:"stable"` StableKF5 string `json:"stableKF5"` Trunk string `json:"trunk"` TrunkKF5 string `json:"trunkKF5"` // Custom fields not found in input data. Calculated by us. Component string `json:"component"` } // Merge merges another i18nData into this i18nData. The other's values always // override unless they are empty. func (i *I18nData) Merge(o I18nData) { if o.Stable != "" { i.Stable = o.Stable } if o.StableKF5 != "" { i.StableKF5 = o.StableKF5 } if o.Trunk != "" { i.Trunk = o.Trunk } if o.TrunkKF5 != "" { i.TrunkKF5 = o.TrunkKF5 } } // Infer infers additional properties of I18nData from its Project. func (i *I18nData) Infer(project *Project) { + if project.Identifier != "" { + // With the move to gitlab we have a new identifier that is used as + // k18n component (and is now per-repo). This replaces the shoddy + // inference from before. + i.Component = project.Identifier + return + } + if project.Repo == "" { return } // Component inference is ported over from releaseme. // Break the full project path down into parts and mangle them until // we get the path under which this project would appear in SVN. parts := strings.Split(project.Path, "/") dropLimit := 2 // Start off with stripping the leading kde/. if parts[0] == "kde" && parts[1] != "workspace" { // Everything but kde/workspace is flattend without the kde part. // kde/workspace on the other hand is kde-workspace. // So, for everything but workspace, drop the kde part. // [kde,workspace] => same // [kde,kdepim-runtime] => [kdepim-runtime] // [kde,kdegraphics,libs] => [kdegraphics,libs] parts = parts[1:] // Shrink the drop limit. When we dropped kde/ we'll effectively have // removed the original assumption of there being two elements to join // as we already removed the first element. Workspace is the best example // of this fact as it is kde-workspace even though pim isn't kde-pim. // That is also why it needs special treatment. dropLimit = 1 } else if parts[0] == "kdesupport" && parts[1] == "phonon" && len(parts) >= 3 { // For phonon the correct mapping rules are not correct as per SVN // r1545471. // It has a nested structure, but this is flattened for i18n. // To mimic this we'll kdesupport/phonon/phonon => kdesupport/phonon // which results in the correct i18n path "/kdesupport/". parts = append(parts[:1], parts[2:]...) dropLimit = 1 } // Ditch last part as that is our name. But only if we in fact have more // parts. Otherwise the last part is the i18n_path of a flat // component. e.g. kdepim-runtime is a component AND the project. if len(parts) > 1 { parts = parts[:len(parts)-1] } // Reduce the path down to 2-1 parts at the most to strip subprojects // [calligra] => same // [frameworks] => same // [workspace] => same // [kdepim-runtime] => same // [kdegraphics,libs] => [kdegraphics] (drop limit was 1) // [extragear,utils,telepathy] => [extragear,utils] (drop limit was 2) for len(parts) > dropLimit { parts = parts[:len(parts)-1] } // The remainder is between 1 and 2 parts long which we'll join to get // the i18n path. // [calligra] => 'calligra' // [frameworks] => 'frameworks' // [kde,workspace] => 'kde-workspace' // [kdepim-runtime] => 'kdepim-runtime' // [kdegraphics] => 'kdegraphics' // [extragear,utils] => 'extragear-utils' i.Component = strings.Join(parts, "-") } // UnmarshalJSON unmarshals the input snake_case attributes into our struct // which will marshal to CamelCase upon output via encoding tags. func (i *I18nData) UnmarshalJSON(data []byte) error { // This would be oh-so unnecessary if the de/encoder simply allowed specifying // an arbitrary tag instead of json so one could use two distinct tags for // input and output -.- m := i18nInputData{} if err := json.Unmarshal(data, &m); err != nil { return err } i.Stable = m.Stable i.StableKF5 = m.StableKF5 i.Trunk = m.Trunk i.TrunkKF5 = m.TrunkKF5 return nil } diff --git a/models/i18n_test.go b/models/i18n_test.go index 8a2070e..989cd8c 100644 --- a/models/i18n_test.go +++ b/models/i18n_test.go @@ -1,65 +1,78 @@ /* Copyright © 2017 Harald Sitter This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package models import ( "path/filepath" "testing" "github.com/stretchr/testify/assert" ) func TestInfer(t *testing.T) { // Testing component inference. Given the infer function a project should // correctly infer the i18n component from the available information. cases := []struct { path string component string }{ {"calligra/krita", "calligra"}, {"kde/workspace/plasma-workspace", "kde-workspace"}, {"kde/kdemultimedia/dragon", "kdemultimedia"}, {"frameworks/solid", "frameworks"}, {"extragear/utils/telepathy/fishy", "extragear-utils"}, // Make sure i18n_path of modules that are also projects get properly // constructed. // https://bugs.kde.org/show_bug.cgi?id=379164 {"kde/kdepim-runtime", "kdepim-runtime"}, // Make sure i18n_path of modules that are inside projects on a third level // nested get properly constructed. // https://bugs.kde.org/show_bug.cgi?id=379161 {"kde/kdegraphics/libs/libksane", "kdegraphics"}, // Phonon does not follow the general rule, it's nested in the project // structure but flattened in i18n. {"kdesupport/phonon/phonon-vlc", "kdesupport"}, // ... in case it gets flattened in project structure as well, let's // ensure it will behave correctly still. {"kdesupport/phonon", "kdesupport"}, } for _, testCase := range cases { t.Run(testCase.path, func(t *testing.T) { i := I18nData{} p := Project{Path: testCase.path, Repo: filepath.Base(testCase.path)} i.Infer(&p) assert.Equal(t, testCase.component, i.Component) }) } } + +func testInferIdentifier(t *testing.T) { + // Not actually an inference. If the Project has an Identifier set, it's the + // component since the gitlab transition. + i := I18nData{} + p := Project{ + Path: "kdesupport/phonon", + Repo: "kdesupport/phonon", + Identifier: "foobar", + } + i.Infer(&p) + assert.Equal(t, "foobar", i.Component) +} diff --git a/models/project.go b/models/project.go index 0452b80..75a2f8c 100644 --- a/models/project.go +++ b/models/project.go @@ -1,29 +1,30 @@ /* Copyright © 2017-2019 Harald Sitter This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package models // Project is the core model of a project entity. type Project struct { - I18n I18nData `yaml:"i18n" json:"i18n"` - Path string `yaml:"projectpath" json:"path"` - Repo string `yaml:"repopath" json:"repo"` - Active bool `yaml:"repoactive" json:"-"` // do not marshal to json, we presently have no use case for it + I18n I18nData `yaml:"i18n" json:"i18n"` + Path string `yaml:"projectpath" json:"path"` + Repo string `yaml:"repopath" json:"repo"` + Active bool `yaml:"repoactive" json:"-"` // do not marshal to json, we presently have no use case for it + Identifier string `yaml:"identifier" json:"-"` // marshal'd via I18nData }