Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/tools/tools/treble/hacksaw/workspace/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 8 kB image not shown  

Quelle  workspace.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// Copyright 2020 Google LLC
//
// 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
//
//     https://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 workspace let's you manage workspaces
package workspace

import (
 "fmt"
 "io/ioutil"
 "os"
 "os/exec"
 "path/filepath"
 "strings"

 "android.googlesource.com/platform/tools/treble.git/hacksaw/bind"
 "android.googlesource.com/platform/tools/treble.git/hacksaw/codebase"
 "android.googlesource.com/platform/tools/treble.git/hacksaw/config"
 "android.googlesource.com/platform/tools/treble.git/hacksaw/git"
)

type Workspace struct {
 composer Composer
 topDir   string
}

func New(bm bind.PathBinder, topDir string) Workspace {
 return Workspace{NewComposer(bm), topDir}
}

// Create workspace
func (w Workspace) Create(workspaceName string, codebaseName string) (string, error) {
 cfg := config.GetConfig()
 _, ok := cfg.Codebases[codebaseName]
 if !ok {
  return "", fmt.Errorf("Codebase %s does not exist", codebaseName)
 }
 if _, ok := cfg.Workspaces[workspaceName]; ok {
  return "", fmt.Errorf("Workspace %s already exists", workspaceName)
 }
 cfg.Workspaces[workspaceName] = codebaseName
 workspaceDir, err := w.GetDir(workspaceName)
 if err != nil {
  return "", err
 }
 if err = os.MkdirAll(workspaceDir, os.ModePerm); err != nil {
  return "", err
 }
 codebaseDir, err := codebase.GetDir(codebaseName)
 if err != nil {
  return "", err
 }
 //TODO: match the order of parameters with Create
 if _, err = w.composer.Compose(codebaseDir, workspaceDir); err != nil {
  return "", err
 }
 return workspaceDir, nil
}

// Recreate workspace
func (w Workspace) Recreate(workspaceName string) (string, error) {
 cfg := config.GetConfig()
 codebaseName, ok := cfg.Workspaces[workspaceName]
 if !ok {
  return "", fmt.Errorf("Workspace %s does not exist", workspaceName)
 }
 workspaceDir, err := w.GetDir(workspaceName)
 if err != nil {
  return "", err
 }
 codebaseDir, err := codebase.GetDir(codebaseName)
 if err != nil {
  return "", err
 }
 if _, err = w.composer.Compose(codebaseDir, workspaceDir); err != nil {
  return "", err
 }
 return workspaceDir, nil
}

// GetDir retrieves the directory of a specific workspace
func (w Workspace) GetDir(workspaceName string) (string, error) {
 cfg := config.GetConfig()
 _, ok := cfg.Workspaces[workspaceName]
 if !ok {
  return "", fmt.Errorf("Workspace %s not found", workspaceName)
 }
 dir := filepath.Join(w.topDir, workspaceName)
 return dir, nil
}

// GetCodebase retrieves the codebase that a workspace belongs to
func (w Workspace) GetCodebase(workspaceName string) (string, error) {
 cfg := config.GetConfig()
 codebase, ok := cfg.Workspaces[workspaceName]
 if !ok {
  return "", fmt.Errorf("Workspace %s not found", workspaceName)
 }
 return codebase, nil
}

//SetTopDir sets the directory that contains all workspaces
func (w *Workspace) SetTopDir(dir string) {
 w.topDir = dir
}

func (w Workspace) List() map[string]string {
 cfg := config.GetConfig()
 list := make(map[string]string)
 for name, codebaseName := range cfg.Workspaces {
  list[name] = codebaseName
 }
 return list
}

func (w Workspace) DetachGitWorktrees(workspaceName string, unbindList []string) error {
 workspaceDir, err := w.GetDir(workspaceName)
 if err != nil {
  return err
 }
 workspaceDir, err = filepath.Abs(workspaceDir)
 if err != nil {
  return err
 }
 //resolve all symlinks so it can be
 //matched to mount paths
 workspaceDir, err = filepath.EvalSymlinks(workspaceDir)
 if err != nil {
  return err
 }
 codebaseName, err := w.GetCodebase(workspaceName)
 if err != nil {
  return err
 }
 codebaseDir, err := codebase.GetDir(codebaseName)
 if err != nil {
  return err
 }
 lister := git.NewRepoLister()
 gitProjects, err := lister.List(codebaseDir)
 if err != nil {
  return err
 }
 gitWorktrees := make(map[string]bool)
 for _, project := range gitProjects {
  gitWorktrees[project] = true
 }
 //projects that were unbound were definitely
 //never git worktrees
 for _, unbindPath := range unbindList {
  project, err := filepath.Rel(workspaceDir, unbindPath)
  if err != nil {
   return err
  }
  if _, ok := gitWorktrees[project]; ok {
   gitWorktrees[project] = false
  }
 }
 for project, isWorktree := range gitWorktrees {
  if !isWorktree {
   continue
  }
  codebaseProject := filepath.Join(codebaseDir, project)
  workspaceProject := filepath.Join(workspaceDir, project)
  _, err = os.Stat(workspaceProject)
  if err == nil {
   //proceed to detach
  } else if os.IsNotExist(err) {
   //just skip if it doesn't exist
   continue
  } else {
   return err
  }
  contents, err := ioutil.ReadDir(workspaceProject)
  if err != nil {
   return err
  }
  if len(contents) == 0 {
   //empty directory, not even a .git
   //not a wortree
   continue
  }
  fmt.Print(".")
  cmd := exec.Command("git",
   "-C", codebaseProject,
   "worktree", "remove", "--force", workspaceProject)
  output, err := cmd.CombinedOutput()
  if err != nil {
   return fmt.Errorf("Command\n%s\nfailed with the following:\n%s\n%s",
    cmd.String(), err.Error(), output)
  }
  cmd = exec.Command("git",
   "-C", codebaseProject,
   "branch", "--delete", "--force", workspaceName)
  output, err = cmd.CombinedOutput()
  if err != nil {
   return fmt.Errorf("Command\n%s\nfailed with the following:\n%s\n%s",
    cmd.String(), err.Error(), output)
  }
 }
 return nil
}

func (w Workspace) Remove(remove string) (*config.Config, error) {
 cfg := config.GetConfig()
 _, ok := cfg.Workspaces[remove]
 if !ok {
  return cfg, fmt.Errorf("Workspace %s not found", remove)
 }
 workspaceDir, err := w.GetDir(remove)
 if err != nil {
  return cfg, err
 }
 unbindList, err := w.composer.Dismantle(workspaceDir)
 if err != nil {
  return cfg, err
 }
 fmt.Print("Detaching worktrees")
 if err = w.DetachGitWorktrees(remove, unbindList); err != nil {
  return cfg, err
 }
 fmt.Print("\n")
 fmt.Println("Removing files")
 if err = os.RemoveAll(workspaceDir); err != nil {
  return cfg, err
 }
 delete(cfg.Workspaces, remove)
 return cfg, err
}

func (w Workspace) Edit(editPath string) (string, string, error) {
 editPath, err := filepath.Abs(editPath)
 if err != nil {
  return "", "", err
 }
 editPath, err = filepath.EvalSymlinks(editPath)
 if err != nil {
  return "", "", err
 }
 relProjectPath, err := w.getReadOnlyProjectFromPath(editPath)
 if err != nil {
  return "", "", err
 }
 workspaceName, err := w.getWorkspaceFromPath(editPath)
 if err != nil {
  return "", "", err
 }
 workspaceDir, err := w.GetDir(workspaceName)
 if err != nil {
  return "", "", err
 }
 codebaseName, err := w.GetCodebase(workspaceName)
 if err != nil {
  return "", "", err
 }
 codebaseDir, err := codebase.GetDir(codebaseName)
 if err != nil {
  return "", "", err
 }
 wsProjectPath := filepath.Join(workspaceDir, relProjectPath)
 if err = w.composer.Unbind(wsProjectPath); err != nil {
  return "", "", err
 }
 //TODO: support editing nested projects
 //the command above unbinds nested child projects but
 //we don't rebind them after checking out an editable project branch
 cbProjectPath := filepath.Join(codebaseDir, relProjectPath)
 branchName := workspaceName
 cmd := exec.Command("git",
  "-C", cbProjectPath,
  "worktree", "add",
  "-b", branchName,
  wsProjectPath)
 output, err := cmd.CombinedOutput()
 if err != nil {
  return "", "", fmt.Errorf("Command\n%s\nfailed with the following:\n%s\n%s",
   cmd.String(), err.Error(), output)
 }
 return branchName, wsProjectPath, err
}

func (w Workspace) getReadOnlyProjectFromPath(inPath string) (string, error) {
 worspaceName, err := w.getWorkspaceFromPath(inPath)
 if err != nil {
  return "", err
 }
 workspacePath, err := w.GetDir(worspaceName)
 if err != nil {
  return "", err
 }
 bindList, err := w.composer.List(workspacePath)
 if err != nil {
  return "", err
 }
 for _, bindPath := range bindList {
  if !strings.HasPrefix(inPath+"/", bindPath+"/") {
   continue
  }
  relProjectPath, err := filepath.Rel(workspacePath, bindPath)
  if err != nil {
   return "", err
  }
  return relProjectPath, nil
 }
 return "", fmt.Errorf("Path %s is already editable", inPath)
}

func (w Workspace) getWorkspaceFromPath(inPath string) (string, error) {
 for workspaceName, _ := range w.List() {
  dir, err := w.GetDir(workspaceName)
  if err != nil {
   return "", err
  }
  if strings.HasPrefix(inPath+"/", dir+"/") {
   return workspaceName, nil
  }
 }
 return "", fmt.Errorf("Path %s is not contained in a workspace", inPath)
}

[Dauer der Verarbeitung: 0.19 Sekunden, vorverarbeitet 2026-06-27]