blob: da6947f064907a91e8e0183dab044b0c16f9903d [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"os"
"path/filepath"
"v.io/jiri/jiri"
"v.io/jiri/project"
"v.io/jiri/runutil"
"v.io/x/lib/cmdline"
)
// TODO(toddw): Remove the upgrade command after the transition to new-style
// manifests is complete.
var flagUpgradeRevert bool
func init() {
cmdUpgrade.Flags.BoolVar(&flagUpgradeRevert, "revert", false, `Revert the upgrade by deleting the $JIRI_ROOT/.jiri_manifest file.`)
}
var cmdUpgrade = &cmdline.Command{
Runner: jiri.RunnerFunc(runUpgrade),
Name: "upgrade",
Short: "Upgrade jiri to new-style manifests",
Long: `
Upgrades jiri to use new-style manifests.
The old (deprecated) behavior only allowed a single manifest repository, located
in $JIRI_ROOT/.manifest. The initial manifest file is located as follows:
1) Use -manifest flag, if non-empty. If it's empty...
2) Use $JIRI_ROOT/.local_manifest file. If it doesn't exist...
3) Use $JIRI_ROOT/.manifest/v2/default.
The new behavior allows multiple manifest repositories, by allowing imports to
specify project attributes describing the remote repository. The -manifest flag
is no longer allowed to be set; the initial manifest file is always located in
$JIRI_ROOT/.jiri_manifest. The .local_manifest file is ignored.
During the transition phase, both old and new behaviors are supported. The jiri
tool uses the existence of the $JIRI_ROOT/.jiri_manifest file as the signal; if
it exists we run the new behavior, otherwise we run the old behavior.
The new behavior includes a "jiri import" command, which writes or updates the
.jiri_manifest file. The new bootstrap procedure runs "jiri import", and it is
intended as a regular command to add imports to your jiri environment.
This upgrade command eases the transition by writing an initial .jiri_manifest
file for you. If you have an existing .local_manifest file, its contents will
be incorporated into the new .jiri_manifest file, and it will be renamed to
.local_manifest.BACKUP. The -revert flag deletes the .jiri_manifest file, and
restores the .local_manifest file.
`,
ArgsName: "<kind>",
ArgsLong: `
<kind> specifies the kind of upgrade, one of "v23" or "fuchsia".
`,
}
func runUpgrade(jirix *jiri.X, args []string) error {
localFile := filepath.Join(jirix.Root, ".local_manifest")
backupFile := localFile + ".BACKUP"
if flagUpgradeRevert {
// Restore .local_manifest.BACKUP if it exists.
switch _, err := jirix.NewSeq().Stat(backupFile); {
case err != nil && !runutil.IsNotExist(err):
return err
case err == nil:
if err := jirix.NewSeq().Rename(backupFile, localFile).Done(); err != nil {
return fmt.Errorf("couldn't restore %v to %v: %v", backupFile, localFile, err)
}
}
// Deleting the .jiri_manifest file reverts to the old behavior.
return jirix.NewSeq().Remove(jirix.JiriManifestFile()).Done()
}
if len(args) != 1 {
return jirix.UsageErrorf("must specify upgrade kind")
}
kind := args[0]
var argRemote, argName, argManifest string
switch kind {
case "v23":
argRemote = "https://vanadium.googlesource.com/manifest"
argName, argManifest = "manifest", "public"
case "fuchsia":
argRemote = "https://fuchsia.googlesource.com/fnl-start"
argName, argManifest = "fnl-start", "manifest/fuchsia"
default:
return jirix.UsageErrorf("unknown upgrade kind %q", kind)
}
// Initialize manifest from .local_manifest.
hasLocalFile := true
manifest, err := project.ManifestFromFile(jirix, localFile)
if err != nil {
if !runutil.IsNotExist(err) {
return err
}
hasLocalFile = false
manifest = &project.Manifest{}
}
oldImports := manifest.Imports
manifest.Imports = nil
for _, oldImport := range oldImports {
if oldImport.Remote != "" {
// This is a new-style remote import, carry it over directly.
manifest.Imports = append(manifest.Imports, oldImport)
continue
}
// This is an old-style import, convert it to the new style.
oldName := oldImport.Name
switch {
case kind == "v23" && oldName == "default":
oldName = "public"
case kind == "fuchsia" && oldName == "default":
oldName = "manifest/fuchsia"
}
manifest.Imports = append(manifest.Imports, project.Import{
Manifest: oldName,
Name: argName,
Remote: argRemote,
})
}
if len(manifest.Imports) == 0 {
manifest.Imports = append(manifest.Imports, project.Import{
Manifest: argManifest,
Name: argName,
Remote: argRemote,
})
}
// Write output to .jiri_manifest file.
outFile := jirix.JiriManifestFile()
if _, err := os.Stat(outFile); err == nil {
return fmt.Errorf("%v already exists", outFile)
}
if err := manifest.ToFile(jirix, outFile); err != nil {
return err
}
// Backup .local_manifest file, if it exists.
if hasLocalFile {
if err := jirix.NewSeq().Rename(localFile, backupFile).Done(); err != nil {
return fmt.Errorf("couldn't backup %v to %v: %v", localFile, backupFile, err)
}
}
return nil
}