187 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			187 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * Copyright (c) 2022 Huawei Device Co., Ltd.
							 | 
						||
| 
								 | 
							
								 * 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.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								package vcs
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"crypto/md5"
							 | 
						||
| 
								 | 
							
									"encoding/xml"
							 | 
						||
| 
								 | 
							
									"fmt"
							 | 
						||
| 
								 | 
							
									"github.com/sirupsen/logrus"
							 | 
						||
| 
								 | 
							
									"os"
							 | 
						||
| 
								 | 
							
									"sort"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type Manifest struct {
							 | 
						||
| 
								 | 
							
									XMLName  xml.Name  `xml:"manifest"`
							 | 
						||
| 
								 | 
							
									Remote   Remote    `xml:"remote"`
							 | 
						||
| 
								 | 
							
									Default  Default   `xml:"default"`
							 | 
						||
| 
								 | 
							
									Projects []Project `xml:"project"`
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type Remote struct {
							 | 
						||
| 
								 | 
							
									Name   string `xml:"name,attr"`
							 | 
						||
| 
								 | 
							
									Fetch  string `xml:"fetch,attr"`
							 | 
						||
| 
								 | 
							
									Review string `xml:"review,attr"`
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type Default struct {
							 | 
						||
| 
								 | 
							
									Remote   string `xml:"remote,attr"`
							 | 
						||
| 
								 | 
							
									Revision string `xml:"revision,attr"`
							 | 
						||
| 
								 | 
							
									SyncJ    string `xml:"sync-j,attr"`
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type Project struct {
							 | 
						||
| 
								 | 
							
									XMLName    xml.Name   `xml:"project"`
							 | 
						||
| 
								 | 
							
									Name       string     `xml:"name,attr"`
							 | 
						||
| 
								 | 
							
									Path       string     `xml:"path,attr,omitempty"`
							 | 
						||
| 
								 | 
							
									Revision   string     `xml:"revision,attr"`
							 | 
						||
| 
								 | 
							
									Remote     string     `xml:"remote,attr,omitempty"`
							 | 
						||
| 
								 | 
							
									CloneDepth string     `xml:"clone-depth,attr,omitempty"`
							 | 
						||
| 
								 | 
							
									LinkFile   []LinkFile `xml:"linkfile,omitempty"`
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type LinkFile struct {
							 | 
						||
| 
								 | 
							
									Src  string `xml:"src,attr"`
							 | 
						||
| 
								 | 
							
									Dest string `xml:"dest,attr"`
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type ProjectUpdate struct {
							 | 
						||
| 
								 | 
							
									P1, P2 *Project
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (p *Project) String() string {
							 | 
						||
| 
								 | 
							
									if p == nil {
							 | 
						||
| 
								 | 
							
										return "<nil>"
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return fmt.Sprintf("<%s>", p.Name)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (p *Project) StructureDiff(p2 *Project) bool {
							 | 
						||
| 
								 | 
							
									if p == nil && p2 != nil || p != nil && p2 == nil {
							 | 
						||
| 
								 | 
							
										return true
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if p == nil && p2 == nil {
							 | 
						||
| 
								 | 
							
										return false
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return p.Name != p2.Name || p.Path != p2.Path || p.Remote != p2.Remote
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (p *Project) Equals(p2 *Project) bool {
							 | 
						||
| 
								 | 
							
									return p.Name == p2.Name && p.Path == p2.Path && p.Remote == p2.Remote && p.Revision == p2.Revision
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func ParseManifestFile(file string) (*Manifest, error) {
							 | 
						||
| 
								 | 
							
									data, err := os.ReadFile(file)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									var m Manifest
							 | 
						||
| 
								 | 
							
									err = xml.Unmarshal(data, &m)
							 | 
						||
| 
								 | 
							
									return &m, err
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (m *Manifest) WriteFile(filePath string) error {
							 | 
						||
| 
								 | 
							
									data, err := xml.MarshalIndent(m, "", "  ")
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									data = append([]byte(xml.Header), data...)
							 | 
						||
| 
								 | 
							
									return os.WriteFile(filePath, data, 0640)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func GetRepoUpdates(m1, m2 *Manifest) (updates []ProjectUpdate, err error) {
							 | 
						||
| 
								 | 
							
									if _, err := m1.Standardize(); err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if _, err := m2.Standardize(); err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									var j int
							 | 
						||
| 
								 | 
							
									for i := 0; i < len(m1.Projects); {
							 | 
						||
| 
								 | 
							
										if m2.Projects[j].Name == m1.Projects[i].Name {
							 | 
						||
| 
								 | 
							
											if !m1.Projects[i].Equals(&m2.Projects[j]) {
							 | 
						||
| 
								 | 
							
												logrus.Infof("%v changes", &m1.Projects[i])
							 | 
						||
| 
								 | 
							
												updates = append(updates, ProjectUpdate{
							 | 
						||
| 
								 | 
							
													P1: &m1.Projects[i],
							 | 
						||
| 
								 | 
							
													P2: &m2.Projects[j],
							 | 
						||
| 
								 | 
							
												})
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											i++
							 | 
						||
| 
								 | 
							
											j++
							 | 
						||
| 
								 | 
							
										} else if m2.Projects[j].Name > m1.Projects[i].Name {
							 | 
						||
| 
								 | 
							
											logrus.Infof("%v removed", &m1.Projects[i])
							 | 
						||
| 
								 | 
							
											updates = append(updates, ProjectUpdate{
							 | 
						||
| 
								 | 
							
												P1: &m1.Projects[i],
							 | 
						||
| 
								 | 
							
												P2: nil,
							 | 
						||
| 
								 | 
							
											})
							 | 
						||
| 
								 | 
							
											i++
							 | 
						||
| 
								 | 
							
										} else { // m2.Projects[j].Name < m1.Projects[i].Name
							 | 
						||
| 
								 | 
							
											logrus.Infof("%v added", &m2.Projects[j])
							 | 
						||
| 
								 | 
							
											updates = append(updates, ProjectUpdate{
							 | 
						||
| 
								 | 
							
												P1: nil,
							 | 
						||
| 
								 | 
							
												P2: &m2.Projects[j],
							 | 
						||
| 
								 | 
							
											})
							 | 
						||
| 
								 | 
							
											j++
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (m *Manifest) UpdateManifestProject(name, path, remote, revision string, add bool) {
							 | 
						||
| 
								 | 
							
									if name == "manifest" {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									for i, p := range m.Projects {
							 | 
						||
| 
								 | 
							
										if p.Name == name {
							 | 
						||
| 
								 | 
							
											if path != "" {
							 | 
						||
| 
								 | 
							
												m.Projects[i].Path = path
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											if remote != "" {
							 | 
						||
| 
								 | 
							
												m.Projects[i].Remote = remote
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											if revision != "" {
							 | 
						||
| 
								 | 
							
												m.Projects[i].Revision = revision
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											return
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if add {
							 | 
						||
| 
								 | 
							
										m.Projects = append(m.Projects, Project{Name: name, Path: path, Revision: revision, Remote: remote})
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (m *Manifest) RemoveManifestProject(name string) {
							 | 
						||
| 
								 | 
							
									for i, p := range m.Projects {
							 | 
						||
| 
								 | 
							
										if p.Name == name {
							 | 
						||
| 
								 | 
							
											m.Projects = append(m.Projects[:i], m.Projects[i:]...)
							 | 
						||
| 
								 | 
							
											return
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (m *Manifest) Standardize() (string, error) {
							 | 
						||
| 
								 | 
							
									sort.Slice(m.Projects, func(i, j int) bool {
							 | 
						||
| 
								 | 
							
										return m.Projects[i].Name < m.Projects[j].Name
							 | 
						||
| 
								 | 
							
									})
							 | 
						||
| 
								 | 
							
									data, err := xml.MarshalIndent(m, "", "  ")
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return "", err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									data = append([]byte(xml.Header), data...)
							 | 
						||
| 
								 | 
							
									sumByte := md5.Sum(data)
							 | 
						||
| 
								 | 
							
									return fmt.Sprintf("%X", sumByte), nil
							 | 
						||
| 
								 | 
							
								}
							 |