1ba991379Sopenharmony_ci/* 2ba991379Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd. 3ba991379Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4ba991379Sopenharmony_ci * you may not use this file except in compliance with the License. 5ba991379Sopenharmony_ci * You may obtain a copy of the License at 6ba991379Sopenharmony_ci * 7ba991379Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8ba991379Sopenharmony_ci * 9ba991379Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10ba991379Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11ba991379Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12ba991379Sopenharmony_ci * See the License for the specific language governing permissions and 13ba991379Sopenharmony_ci * limitations under the License. 14ba991379Sopenharmony_ci */ 15ba991379Sopenharmony_ci 16ba991379Sopenharmony_cipackage vcs 17ba991379Sopenharmony_ci 18ba991379Sopenharmony_ciimport ( 19ba991379Sopenharmony_ci "crypto/md5" 20ba991379Sopenharmony_ci "encoding/xml" 21ba991379Sopenharmony_ci "fmt" 22ba991379Sopenharmony_ci "github.com/sirupsen/logrus" 23ba991379Sopenharmony_ci "os" 24ba991379Sopenharmony_ci "sort" 25ba991379Sopenharmony_ci) 26ba991379Sopenharmony_ci 27ba991379Sopenharmony_citype Manifest struct { 28ba991379Sopenharmony_ci XMLName xml.Name `xml:"manifest"` 29ba991379Sopenharmony_ci Remote Remote `xml:"remote"` 30ba991379Sopenharmony_ci Default Default `xml:"default"` 31ba991379Sopenharmony_ci Projects []Project `xml:"project"` 32ba991379Sopenharmony_ci} 33ba991379Sopenharmony_ci 34ba991379Sopenharmony_citype Remote struct { 35ba991379Sopenharmony_ci Name string `xml:"name,attr"` 36ba991379Sopenharmony_ci Fetch string `xml:"fetch,attr"` 37ba991379Sopenharmony_ci Review string `xml:"review,attr"` 38ba991379Sopenharmony_ci} 39ba991379Sopenharmony_ci 40ba991379Sopenharmony_citype Default struct { 41ba991379Sopenharmony_ci Remote string `xml:"remote,attr"` 42ba991379Sopenharmony_ci Revision string `xml:"revision,attr"` 43ba991379Sopenharmony_ci SyncJ string `xml:"sync-j,attr"` 44ba991379Sopenharmony_ci} 45ba991379Sopenharmony_ci 46ba991379Sopenharmony_citype Project struct { 47ba991379Sopenharmony_ci XMLName xml.Name `xml:"project"` 48ba991379Sopenharmony_ci Name string `xml:"name,attr"` 49ba991379Sopenharmony_ci Path string `xml:"path,attr,omitempty"` 50ba991379Sopenharmony_ci Revision string `xml:"revision,attr"` 51ba991379Sopenharmony_ci Remote string `xml:"remote,attr,omitempty"` 52ba991379Sopenharmony_ci CloneDepth string `xml:"clone-depth,attr,omitempty"` 53ba991379Sopenharmony_ci LinkFile []LinkFile `xml:"linkfile,omitempty"` 54ba991379Sopenharmony_ci} 55ba991379Sopenharmony_ci 56ba991379Sopenharmony_citype LinkFile struct { 57ba991379Sopenharmony_ci Src string `xml:"src,attr"` 58ba991379Sopenharmony_ci Dest string `xml:"dest,attr"` 59ba991379Sopenharmony_ci} 60ba991379Sopenharmony_ci 61ba991379Sopenharmony_citype ProjectUpdate struct { 62ba991379Sopenharmony_ci P1, P2 *Project 63ba991379Sopenharmony_ci} 64ba991379Sopenharmony_ci 65ba991379Sopenharmony_cifunc (p *Project) String() string { 66ba991379Sopenharmony_ci if p == nil { 67ba991379Sopenharmony_ci return "<nil>" 68ba991379Sopenharmony_ci } 69ba991379Sopenharmony_ci return fmt.Sprintf("<%s>", p.Name) 70ba991379Sopenharmony_ci} 71ba991379Sopenharmony_ci 72ba991379Sopenharmony_cifunc (p *Project) StructureDiff(p2 *Project) bool { 73ba991379Sopenharmony_ci if p == nil && p2 != nil || p != nil && p2 == nil { 74ba991379Sopenharmony_ci return true 75ba991379Sopenharmony_ci } 76ba991379Sopenharmony_ci if p == nil && p2 == nil { 77ba991379Sopenharmony_ci return false 78ba991379Sopenharmony_ci } 79ba991379Sopenharmony_ci return p.Name != p2.Name || p.Path != p2.Path || p.Remote != p2.Remote 80ba991379Sopenharmony_ci} 81ba991379Sopenharmony_ci 82ba991379Sopenharmony_cifunc (p *Project) Equals(p2 *Project) bool { 83ba991379Sopenharmony_ci return p.Name == p2.Name && p.Path == p2.Path && p.Remote == p2.Remote && p.Revision == p2.Revision 84ba991379Sopenharmony_ci} 85ba991379Sopenharmony_ci 86ba991379Sopenharmony_cifunc ParseManifestFile(file string) (*Manifest, error) { 87ba991379Sopenharmony_ci data, err := os.ReadFile(file) 88ba991379Sopenharmony_ci if err != nil { 89ba991379Sopenharmony_ci return nil, err 90ba991379Sopenharmony_ci } 91ba991379Sopenharmony_ci var m Manifest 92ba991379Sopenharmony_ci err = xml.Unmarshal(data, &m) 93ba991379Sopenharmony_ci return &m, err 94ba991379Sopenharmony_ci} 95ba991379Sopenharmony_ci 96ba991379Sopenharmony_cifunc (m *Manifest) WriteFile(filePath string) error { 97ba991379Sopenharmony_ci data, err := xml.MarshalIndent(m, "", " ") 98ba991379Sopenharmony_ci if err != nil { 99ba991379Sopenharmony_ci return err 100ba991379Sopenharmony_ci } 101ba991379Sopenharmony_ci data = append([]byte(xml.Header), data...) 102ba991379Sopenharmony_ci return os.WriteFile(filePath, data, 0640) 103ba991379Sopenharmony_ci} 104ba991379Sopenharmony_ci 105ba991379Sopenharmony_cifunc GetRepoUpdates(m1, m2 *Manifest) (updates []ProjectUpdate, err error) { 106ba991379Sopenharmony_ci if _, err := m1.Standardize(); err != nil { 107ba991379Sopenharmony_ci return nil, err 108ba991379Sopenharmony_ci } 109ba991379Sopenharmony_ci if _, err := m2.Standardize(); err != nil { 110ba991379Sopenharmony_ci return nil, err 111ba991379Sopenharmony_ci } 112ba991379Sopenharmony_ci var j int 113ba991379Sopenharmony_ci for i := 0; i < len(m1.Projects); { 114ba991379Sopenharmony_ci if m2.Projects[j].Name == m1.Projects[i].Name { 115ba991379Sopenharmony_ci if !m1.Projects[i].Equals(&m2.Projects[j]) { 116ba991379Sopenharmony_ci logrus.Infof("%v changes", &m1.Projects[i]) 117ba991379Sopenharmony_ci updates = append(updates, ProjectUpdate{ 118ba991379Sopenharmony_ci P1: &m1.Projects[i], 119ba991379Sopenharmony_ci P2: &m2.Projects[j], 120ba991379Sopenharmony_ci }) 121ba991379Sopenharmony_ci } 122ba991379Sopenharmony_ci i++ 123ba991379Sopenharmony_ci j++ 124ba991379Sopenharmony_ci } else if m2.Projects[j].Name > m1.Projects[i].Name { 125ba991379Sopenharmony_ci logrus.Infof("%v removed", &m1.Projects[i]) 126ba991379Sopenharmony_ci updates = append(updates, ProjectUpdate{ 127ba991379Sopenharmony_ci P1: &m1.Projects[i], 128ba991379Sopenharmony_ci P2: nil, 129ba991379Sopenharmony_ci }) 130ba991379Sopenharmony_ci i++ 131ba991379Sopenharmony_ci } else { // m2.Projects[j].Name < m1.Projects[i].Name 132ba991379Sopenharmony_ci logrus.Infof("%v added", &m2.Projects[j]) 133ba991379Sopenharmony_ci updates = append(updates, ProjectUpdate{ 134ba991379Sopenharmony_ci P1: nil, 135ba991379Sopenharmony_ci P2: &m2.Projects[j], 136ba991379Sopenharmony_ci }) 137ba991379Sopenharmony_ci j++ 138ba991379Sopenharmony_ci } 139ba991379Sopenharmony_ci } 140ba991379Sopenharmony_ci return 141ba991379Sopenharmony_ci} 142ba991379Sopenharmony_ci 143ba991379Sopenharmony_cifunc (m *Manifest) UpdateManifestProject(name, path, remote, revision string, add bool) { 144ba991379Sopenharmony_ci if name == "manifest" { 145ba991379Sopenharmony_ci return 146ba991379Sopenharmony_ci } 147ba991379Sopenharmony_ci for i, p := range m.Projects { 148ba991379Sopenharmony_ci if p.Name == name { 149ba991379Sopenharmony_ci if path != "" { 150ba991379Sopenharmony_ci m.Projects[i].Path = path 151ba991379Sopenharmony_ci } 152ba991379Sopenharmony_ci if remote != "" { 153ba991379Sopenharmony_ci m.Projects[i].Remote = remote 154ba991379Sopenharmony_ci } 155ba991379Sopenharmony_ci if revision != "" { 156ba991379Sopenharmony_ci m.Projects[i].Revision = revision 157ba991379Sopenharmony_ci } 158ba991379Sopenharmony_ci return 159ba991379Sopenharmony_ci } 160ba991379Sopenharmony_ci } 161ba991379Sopenharmony_ci if add { 162ba991379Sopenharmony_ci m.Projects = append(m.Projects, Project{Name: name, Path: path, Revision: revision, Remote: remote}) 163ba991379Sopenharmony_ci } 164ba991379Sopenharmony_ci} 165ba991379Sopenharmony_ci 166ba991379Sopenharmony_cifunc (m *Manifest) RemoveManifestProject(name string) { 167ba991379Sopenharmony_ci for i, p := range m.Projects { 168ba991379Sopenharmony_ci if p.Name == name { 169ba991379Sopenharmony_ci m.Projects = append(m.Projects[:i], m.Projects[i:]...) 170ba991379Sopenharmony_ci return 171ba991379Sopenharmony_ci } 172ba991379Sopenharmony_ci } 173ba991379Sopenharmony_ci} 174ba991379Sopenharmony_ci 175ba991379Sopenharmony_cifunc (m *Manifest) Standardize() (string, error) { 176ba991379Sopenharmony_ci sort.Slice(m.Projects, func(i, j int) bool { 177ba991379Sopenharmony_ci return m.Projects[i].Name < m.Projects[j].Name 178ba991379Sopenharmony_ci }) 179ba991379Sopenharmony_ci data, err := xml.MarshalIndent(m, "", " ") 180ba991379Sopenharmony_ci if err != nil { 181ba991379Sopenharmony_ci return "", err 182ba991379Sopenharmony_ci } 183ba991379Sopenharmony_ci data = append([]byte(xml.Header), data...) 184ba991379Sopenharmony_ci sumByte := md5.Sum(data) 185ba991379Sopenharmony_ci return fmt.Sprintf("%X", sumByte), nil 186ba991379Sopenharmony_ci} 187