Merge "TBR: Revert "devtools: Bump timeout for v23-proxy-integration-test to 30 min.""
diff --git a/data/COPYRIGHT b/data/COPYRIGHT
index 3c28650..a26470e 100644
--- a/data/COPYRIGHT
+++ b/data/COPYRIGHT
@@ -1,3 +1,3 @@
-Copyright 2015 The Vanadium Authors. All rights reserved.
+Copyright [YEAR] 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.
\ No newline at end of file
diff --git a/jiri-copyright/copyright.go b/jiri-copyright/copyright.go
index 38a2792..cb71550 100644
--- a/jiri-copyright/copyright.go
+++ b/jiri-copyright/copyright.go
@@ -20,7 +20,9 @@
"os"
"path/filepath"
"regexp"
+ "strconv"
"strings"
+ "time"
"v.io/jiri"
"v.io/jiri/collect"
@@ -421,7 +423,8 @@
if err != nil {
return nil, err
}
- result.Copyright = string(bytes)
+ currentYear := strconv.Itoa(time.Now().Year())
+ result.Copyright = strings.Replace(string(bytes), "[YEAR]", currentYear, 1)
return &result, nil
}
diff --git a/jiri-profile-v23/mojo_profile/mojo.go b/jiri-profile-v23/mojo_profile/mojo.go
index e4d043d..229404b 100644
--- a/jiri-profile-v23/mojo_profile/mojo.go
+++ b/jiri-profile-v23/mojo_profile/mojo.go
@@ -10,6 +10,7 @@
"flag"
"fmt"
"io/ioutil"
+ "os"
"path/filepath"
"strings"
@@ -230,7 +231,32 @@
sdkVersion: "39488b961eb9dca8c6ca4a2cc0d693dd13db29e3",
androidPlatformToolsVersion: "2219198",
},
- }, "7"),
+ "8": &versionSpec{
+ serviceNames: []string{
+ "authenticating_url_loader_interceptor.mojo",
+ "compositor_service.mojo",
+ "dart_content_handler.mojo",
+ "debugger.mojo",
+ "files.mojo",
+ "input_manager_service.mojo",
+ "launcher.mojo",
+ "view_manager_service.mojo",
+ "tracing.mojo",
+ },
+ serviceNamesAndroid: []string{
+ "shortcut.mojo",
+ },
+ serviceNamesLinux: []string{
+ "authentication.mojo",
+ },
+ buildVersionAndroid: "92b330f6dedb4d880eb66e384a28b1a4de2f6ba2",
+ buildVersionLinux: "92b330f6dedb4d880eb66e384a28b1a4de2f6ba2",
+ devtoolsVersion: "6a6098eb787ea88af5ef8e2978074ad57ce6ebeb",
+ networkServiceVersion: "0a814ed5512598e595c0ae7975a09d90a7a54e90",
+ sdkVersion: "465117ff5f34a8ef48b6a94d57f081e3c8e77ca5",
+ androidPlatformToolsVersion: "2219198",
+ },
+ }, "8"),
}
profilesmanager.Register(m)
}
@@ -419,14 +445,15 @@
func (m *Manager) installMojoSdk(jirix *jiri.X, outDir string) error {
fn := func() error {
seq := jirix.NewSeq()
+ srcDir := filepath.Join(outDir, "src")
// TODO(nlacasse): At some point Mojo needs to change the structure of
// their repo so that go packages occur with correct paths. Until then
// we'll clone into src/mojo/public so that go import paths work.
- repoDst := filepath.Join(outDir, "src", "mojo", "public")
+ publicDir := filepath.Join(srcDir, "mojo", "public")
seq.
- MkdirAll(repoDst, profilesutil.DefaultDirPerm).
- Pushd(repoDst).
- Call(func() error { return gitutil.New(jirix.NewSeq()).CloneRecursive(mojoSdkRemote, repoDst) }, "git clone --recursive %s", mojoSdkRemote).
+ MkdirAll(publicDir, profilesutil.DefaultDirPerm).
+ Pushd(publicDir).
+ Call(func() error { return gitutil.New(jirix.NewSeq()).CloneRecursive(mojoSdkRemote, publicDir) }, "git clone --recursive %s", mojoSdkRemote).
Call(func() error { return gitutil.New(jirix.NewSeq()).Reset(m.spec.sdkVersion) }, "git reset --hard %s", m.spec.sdkVersion).
Popd()
@@ -448,51 +475,56 @@
Popd()
servicesSrc := filepath.Join(tmpMojoCheckout, "mojo", "services")
- servicesDst := filepath.Join(outDir, "src", "mojo", "services")
- seq.Rename(servicesSrc, servicesDst)
+ servicesDir := filepath.Join(srcDir, "mojo", "services")
+ seq.Rename(servicesSrc, servicesDir)
- // Find all .mojom files.
- var mojomFilesBuffer bytes.Buffer
- if err := jirix.NewSeq().Capture(&mojomFilesBuffer, nil).Last("find", outDir, "-name", "*.mojom"); err != nil {
- return err
+ // Generate mojom bindings.
+ seq.Pushd(srcDir)
+
+ // Fetch the mojom compiler.
+ bindingsDir := filepath.Join(publicDir, "tools", "bindings")
+ compilerDir := filepath.Join(bindingsDir, "mojom_tool", "bin")
+ compilerName := "mojom"
+ if _, err := os.Stat(compilerDir); os.IsNotExist(err) {
+ // For an old versions < 8.
+ compilerDir = filepath.Join(bindingsDir, "mojom_parser", "bin")
+ compilerName = "mojom_parser"
}
- mojomFiles := strings.Split(mojomFilesBuffer.String(), "\n")
-
- // Generate the mojom.go files from all mojom files.
- seq.Pushd(filepath.Join(outDir, "src"))
- // Fetch the mojom compiler
- compilerDir := filepath.Join(outDir, "src", "mojo", "public", "tools", "bindings", "mojom_parser", "bin")
-
fetchCompiler := func(arch string) error {
- hash, err := ioutil.ReadFile(filepath.Join(compilerDir, arch, "mojom_parser.sha1"))
+ hash, err := ioutil.ReadFile(filepath.Join(compilerDir, arch, compilerName+".sha1"))
if err != nil {
return err
}
binary := mojoCompilerUrl(arch, string(hash))
- return profilesutil.Fetch(jirix, filepath.Join(compilerDir, arch, "mojom_parser"), binary)
+ return profilesutil.Fetch(jirix, filepath.Join(compilerDir, arch, compilerName), binary)
}
seq.
Call(func() error { return fetchCompiler("linux64") }, "fetch linux64 mojom compiler").
- Chmod(filepath.Join(compilerDir, "linux64", "mojom_parser"), 0755).
+ Chmod(filepath.Join(compilerDir, "linux64", compilerName), 0755).
Call(func() error { return fetchCompiler("mac64") }, "fetch mac64 mojom compiler").
- Chmod(filepath.Join(compilerDir, "mac64", "mojom_parser"), 0755)
- genMojomTool := filepath.Join(outDir, "src", "mojo", "public", "tools", "bindings", "mojom_bindings_generator.py")
+ Chmod(filepath.Join(compilerDir, "mac64", compilerName), 0755)
+
+ // Find all .mojom files excluding ones for testing.
+ var mojomFilesBuffer bytes.Buffer
+ if err := jirix.NewSeq().Capture(&mojomFilesBuffer, nil).Last("find", srcDir, "-name", "*.mojom"); err != nil {
+ return err
+ }
+ mojomFiles := strings.Split(strings.TrimSpace(mojomFilesBuffer.String()), "\n")
+
+ genDir := filepath.Join(outDir, "gen")
+ genMojomTool := filepath.Join(bindingsDir, "mojom_bindings_generator.py")
for _, mojomFile := range mojomFiles {
- trimmedFile := strings.TrimSpace(mojomFile)
- if trimmedFile == "" {
- continue
- }
seq.Run(genMojomTool,
"--use_bundled_pylibs",
- "-g", "go",
- "-o", filepath.Join("..", "gen"),
- "-I", ".",
- "-I", servicesDst,
"--generate-type-info",
- trimmedFile)
+ "--no-gen-imports",
+ "-d", ".",
+ "-I", servicesDir,
+ "-g", "go,java",
+ "-o", genDir,
+ mojomFile)
}
seq.Popd()
-
return seq.Done()
}
diff --git a/madb/clear_data.go b/madb/clear_data.go
new file mode 100644
index 0000000..d058afb
--- /dev/null
+++ b/madb/clear_data.go
@@ -0,0 +1,62 @@
+// 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"
+
+ "v.io/x/lib/cmdline"
+ "v.io/x/lib/gosh"
+)
+
+func init() {
+ initializeIDCacheFlags(&cmdMadbClearData.Flags)
+}
+
+var cmdMadbClearData = &cmdline.Command{
+ Runner: subCommandRunner{initMadbClearData, runMadbClearDataForDevice},
+ Name: "clear-data",
+ Short: "Clear your app data from all devices",
+ Long: `
+Clears your app data from all devices.
+
+`,
+ ArgsName: "[<application_id>]",
+ ArgsLong: `
+<application_id> is usually the package name where the activities are defined.
+(See: http://tools.android.com/tech-docs/new-build-system/applicationid-vs-packagename)
+
+
+If the application ID is not specified, madb automatically determines which app to be cleared, based
+on the build scripts found in the current working directory.
+
+If the working directory contains a Gradle Android project (i.e., has "build.gradle"), run a small
+Gradle script to extract the application ID. In this case, the extracted ID is cached, so that
+"madb clear-data" can be repeated without even running the Gradle script again. The ID can be
+re-extracted by clearing the cache by providing "-clear-cache" flag.
+`,
+}
+
+func initMadbClearData(env *cmdline.Env, args []string) ([]string, error) {
+ return initMadbCommand(env, args, false, false)
+}
+
+func runMadbClearDataForDevice(env *cmdline.Env, args []string, d device) error {
+ sh := gosh.NewShell(nil)
+ defer sh.Cleanup()
+
+ sh.ContinueOnError = true
+
+ if len(args) == 1 {
+ appID := args[0]
+
+ // TODO(youngseokyoon): maybe do something equivalent for flutter?
+ cmdArgs := []string{"-s", d.Serial, "shell", "pm", "clear", appID}
+ cmd := sh.Cmd("adb", cmdArgs...)
+ return runGoshCommandForDevice(cmd, d)
+ }
+
+ return fmt.Errorf("No arguments are provided and failed to extract the id from the build scripts.")
+}
diff --git a/madb/doc.go b/madb/doc.go
index 581ab07..21df511 100644
--- a/madb/doc.go
+++ b/madb/doc.go
@@ -15,12 +15,13 @@
madb [flags] <command>
The madb commands are:
+ clear-data Clear your app data from all devices
exec Run the provided adb command on all devices and emulators
concurrently
+ name Manage device nicknames
start Launch your app on all devices
stop Stop your app on all devices
uninstall Uninstall your app from all devices
- name Manage device nicknames
help Display help for commands or topics
The madb flags are:
@@ -29,8 +30,10 @@
-e=false
Restrict the command to only run on emulators.
-n=
- Comma-separated device serials, qualifiers, or nicknames (set by 'madb
- name'). Command will be run only on specified devices.
+ Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+ '@2'), or nicknames (set by 'madb name'). A device index is specified by an
+ '@' sign followed by the index of the device in the output of 'adb devices'
+ command, starting from 1. Command will be run only on specified devices.
The global flags are:
-metadata=<just specify -metadata to activate>
@@ -38,6 +41,50 @@
-time=false
Dump timing information to stderr before exiting the program.
+Madb clear-data - Clear your app data from all devices
+
+Clears your app data from all devices.
+
+Usage:
+ madb clear-data [flags] [<application_id>]
+
+<application_id> is usually the package name where the activities are defined.
+(See:
+http://tools.android.com/tech-docs/new-build-system/applicationid-vs-packagename)
+
+If the application ID is not specified, madb automatically determines which app
+to be cleared, based on the build scripts found in the current working
+directory.
+
+If the working directory contains a Gradle Android project (i.e., has
+"build.gradle"), run a small Gradle script to extract the application ID. In
+this case, the extracted ID is cached, so that "madb clear-data" can be repeated
+without even running the Gradle script again. The ID can be re-extracted by
+clearing the cache by providing "-clear-cache" flag.
+
+The madb clear-data flags are:
+ -clear-cache=false
+ Clear the cache and re-extract the application ID and the main activity name.
+ Only takes effect when no arguments are provided.
+ -module=
+ Specify which application module to use, when the current directory is the
+ top level Gradle project containing multiple sub-modules. When not
+ specified, the first available application module is used. Only takes effect
+ when no arguments are provided.
+ -variant=
+ Specify which build variant to use. When not specified, the first available
+ build variant is used. Only takes effect when no arguments are provided.
+
+ -d=false
+ Restrict the command to only run on real devices.
+ -e=false
+ Restrict the command to only run on emulators.
+ -n=
+ Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+ '@2'), or nicknames (set by 'madb name'). A device index is specified by an
+ '@' sign followed by the index of the device in the output of 'adb devices'
+ command, starting from 1. Command will be run only on specified devices.
+
Madb exec - Run the provided adb command on all devices and emulators concurrently
Runs the provided adb command on all devices and emulators concurrently.
@@ -63,8 +110,140 @@
-e=false
Restrict the command to only run on emulators.
-n=
- Comma-separated device serials, qualifiers, or nicknames (set by 'madb
- name'). Command will be run only on specified devices.
+ Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+ '@2'), or nicknames (set by 'madb name'). A device index is specified by an
+ '@' sign followed by the index of the device in the output of 'adb devices'
+ command, starting from 1. Command will be run only on specified devices.
+
+Madb name - Manage device nicknames
+
+Manages device nicknames, which are meant to be more human-friendly compared to
+the device serials provided by adb tool.
+
+NOTE: Device specifier flags (-d, -e, -n) are ignored in all 'madb name'
+commands.
+
+Usage:
+ madb name [flags] <command>
+
+The madb name commands are:
+ set Set a nickname to be used in place of the device serial.
+ unset Unset a nickname set by the 'madb name set' command.
+ list List all the existing nicknames.
+ clear-all Clear all the existing nicknames.
+
+The madb name flags are:
+ -d=false
+ Restrict the command to only run on real devices.
+ -e=false
+ Restrict the command to only run on emulators.
+ -n=
+ Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+ '@2'), or nicknames (set by 'madb name'). A device index is specified by an
+ '@' sign followed by the index of the device in the output of 'adb devices'
+ command, starting from 1. Command will be run only on specified devices.
+
+Madb name set
+
+Sets a human-friendly nickname that can be used when specifying the device in
+any madb commands.
+
+The device serial can be obtain using the 'adb devices -l' command. For example,
+consider the following example output:
+
+ HT4BVWV00023 device usb:3-3.4.2 product:volantisg model:Nexus_9 device:flounder_lte
+
+The first value, 'HT4BVWV00023', is the device serial. To assign a nickname for
+this device, run the following command:
+
+ madb name set HT4BVWV00023 MyTablet
+
+and it will assign the 'MyTablet' nickname to the device serial 'HT4BVWV00023'.
+The alternative device specifiers (e.g., 'usb:3-3.4.2', 'product:volantisg') can
+also have nicknames.
+
+When a nickname is set for a device serial, the nickname can be used to specify
+the device within madb commands.
+
+There can only be one nickname for a device serial. When the 'madb name set'
+command is invoked with a device serial with an already assigned nickname, the
+old one will be replaced with the newly provided one.
+
+Usage:
+ madb name set [flags] <device_serial> <nickname>
+
+<device_serial> is a device serial (e.g., 'HT4BVWV00023') or an alternative
+device specifier (e.g., 'usb:3-3.4.2') obtained from 'adb devices -l' command
+<nickname> is an alpha-numeric string with no special characters or spaces.
+
+The madb name set flags are:
+ -d=false
+ Restrict the command to only run on real devices.
+ -e=false
+ Restrict the command to only run on emulators.
+ -n=
+ Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+ '@2'), or nicknames (set by 'madb name'). A device index is specified by an
+ '@' sign followed by the index of the device in the output of 'adb devices'
+ command, starting from 1. Command will be run only on specified devices.
+
+Madb name unset
+
+Unsets a nickname assigned by the 'madb name set' command. Either the device
+serial or the assigned nickname can be specified to remove the mapping.
+
+Usage:
+ madb name unset [flags] <device_serial | nickname>
+
+There should be only one argument, which is either the device serial or the
+nickname.
+
+The madb name unset flags are:
+ -d=false
+ Restrict the command to only run on real devices.
+ -e=false
+ Restrict the command to only run on emulators.
+ -n=
+ Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+ '@2'), or nicknames (set by 'madb name'). A device index is specified by an
+ '@' sign followed by the index of the device in the output of 'adb devices'
+ command, starting from 1. Command will be run only on specified devices.
+
+Madb name list
+
+Lists all the currently stored nicknames of device serials.
+
+Usage:
+ madb name list [flags]
+
+The madb name list flags are:
+ -d=false
+ Restrict the command to only run on real devices.
+ -e=false
+ Restrict the command to only run on emulators.
+ -n=
+ Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+ '@2'), or nicknames (set by 'madb name'). A device index is specified by an
+ '@' sign followed by the index of the device in the output of 'adb devices'
+ command, starting from 1. Command will be run only on specified devices.
+
+Madb name clear-all
+
+Clears all the currently stored nicknames of device serials.
+
+Usage:
+ madb name clear-all [flags]
+
+The madb name clear-all flags are:
+ -d=false
+ Restrict the command to only run on real devices.
+ -e=false
+ Restrict the command to only run on emulators.
+ -n=
+ Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+ '@2'), or nicknames (set by 'madb name'). A device index is specified by an
+ '@' sign followed by the index of the device in the output of 'adb devices'
+ command, starting from 1. Command will be run only on specified devices.
Madb start - Launch your app on all devices
@@ -119,8 +298,10 @@
-e=false
Restrict the command to only run on emulators.
-n=
- Comma-separated device serials, qualifiers, or nicknames (set by 'madb
- name'). Command will be run only on specified devices.
+ Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+ '@2'), or nicknames (set by 'madb name'). A device index is specified by an
+ '@' sign followed by the index of the device in the output of 'adb devices'
+ command, starting from 1. Command will be run only on specified devices.
Madb stop - Stop your app on all devices
@@ -164,8 +345,10 @@
-e=false
Restrict the command to only run on emulators.
-n=
- Comma-separated device serials, qualifiers, or nicknames (set by 'madb
- name'). Command will be run only on specified devices.
+ Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+ '@2'), or nicknames (set by 'madb name'). A device index is specified by an
+ '@' sign followed by the index of the device in the output of 'adb devices'
+ command, starting from 1. Command will be run only on specified devices.
Madb uninstall - Uninstall your app from all devices
@@ -208,125 +391,10 @@
-e=false
Restrict the command to only run on emulators.
-n=
- Comma-separated device serials, qualifiers, or nicknames (set by 'madb
- name'). Command will be run only on specified devices.
-
-Madb name - Manage device nicknames
-
-Manages device nicknames, which are meant to be more human-friendly compared to
-the device serials provided by adb tool.
-
-Usage:
- madb name [flags] <command>
-
-The madb name commands are:
- set Set a nickname to be used in place of the device serial.
- unset Unset a nickname set by the 'madb name set' command.
- list List all the existing nicknames.
- clear-all Clear all the existing nicknames.
-
-The madb name flags are:
- -d=false
- Restrict the command to only run on real devices.
- -e=false
- Restrict the command to only run on emulators.
- -n=
- Comma-separated device serials, qualifiers, or nicknames (set by 'madb
- name'). Command will be run only on specified devices.
-
-Madb name set
-
-Sets a human-friendly nickname that can be used when specifying the device in
-any madb commands.
-
-The device serial can be obtain using the 'adb devices -l' command. For example,
-consider the following example output:
-
- HT4BVWV00023 device usb:3-3.4.2 product:volantisg model:Nexus_9 device:flounder_lte
-
-The first value, 'HT4BVWV00023', is the device serial. To assign a nickname for
-this device, run the following command:
-
- madb name set HT4BVWV00023 MyTablet
-
-and it will assign the 'MyTablet' nickname to the device serial 'HT4BVWV00023'.
-The alternative device specifiers (e.g., 'usb:3-3.4.2', 'product:volantisg') can
-also have nicknames.
-
-When a nickname is set for a device serial, the nickname can be used to specify
-the device within madb commands.
-
-There can only be one nickname for a device serial. When the 'madb name set'
-command is invoked with a device serial with an already assigned nickname, the
-old one will be replaced with the newly provided one.
-
-Usage:
- madb name set [flags] <device_serial> <nickname>
-
-<device_serial> is a device serial (e.g., 'HT4BVWV00023') or an alternative
-device specifier (e.g., 'usb:3-3.4.2') obtained from 'adb devices -l' command
-<nickname> is an alpha-numeric string with no special characters or spaces.
-
-The madb name set flags are:
- -d=false
- Restrict the command to only run on real devices.
- -e=false
- Restrict the command to only run on emulators.
- -n=
- Comma-separated device serials, qualifiers, or nicknames (set by 'madb
- name'). Command will be run only on specified devices.
-
-Madb name unset
-
-Unsets a nickname assigned by the 'madb name set' command. Either the device
-serial or the assigned nickname can be specified to remove the mapping.
-
-Usage:
- madb name unset [flags] <device_serial | nickname>
-
-There should be only one argument, which is either the device serial or the
-nickname.
-
-The madb name unset flags are:
- -d=false
- Restrict the command to only run on real devices.
- -e=false
- Restrict the command to only run on emulators.
- -n=
- Comma-separated device serials, qualifiers, or nicknames (set by 'madb
- name'). Command will be run only on specified devices.
-
-Madb name list
-
-Lists all the currently stored nicknames of device serials.
-
-Usage:
- madb name list [flags]
-
-The madb name list flags are:
- -d=false
- Restrict the command to only run on real devices.
- -e=false
- Restrict the command to only run on emulators.
- -n=
- Comma-separated device serials, qualifiers, or nicknames (set by 'madb
- name'). Command will be run only on specified devices.
-
-Madb name clear-all
-
-Clears all the currently stored nicknames of device serials.
-
-Usage:
- madb name clear-all [flags]
-
-The madb name clear-all flags are:
- -d=false
- Restrict the command to only run on real devices.
- -e=false
- Restrict the command to only run on emulators.
- -n=
- Comma-separated device serials, qualifiers, or nicknames (set by 'madb
- name'). Command will be run only on specified devices.
+ Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+ '@2'), or nicknames (set by 'madb name'). A device index is specified by an
+ '@' sign followed by the index of the device in the output of 'adb devices'
+ command, starting from 1. Command will be run only on specified devices.
Madb help - Display help for commands or topics
diff --git a/madb/madb.go b/madb/madb.go
index 92c2db9..7078841 100644
--- a/madb/madb.go
+++ b/madb/madb.go
@@ -16,6 +16,7 @@
"os/exec"
"path"
"path/filepath"
+ "strconv"
"strings"
"sync"
@@ -39,7 +40,7 @@
func init() {
cmdMadb.Flags.BoolVar(&allDevicesFlag, "d", false, `Restrict the command to only run on real devices.`)
cmdMadb.Flags.BoolVar(&allEmulatorsFlag, "e", false, `Restrict the command to only run on emulators.`)
- cmdMadb.Flags.StringVar(&devicesFlag, "n", "", `Comma-separated device serials, qualifiers, or nicknames (set by 'madb name'). Command will be run only on specified devices.`)
+ cmdMadb.Flags.StringVar(&devicesFlag, "n", "", `Comma-separated device serials, qualifiers, device indices (e.g., '@1', '@2'), or nicknames (set by 'madb name'). A device index is specified by an '@' sign followed by the index of the device in the output of 'adb devices' command, starting from 1. Command will be run only on specified devices.`)
// Store the current working directory.
var err error
@@ -57,7 +58,7 @@
}
var cmdMadb = &cmdline.Command{
- Children: []*cmdline.Command{cmdMadbExec, cmdMadbStart, cmdMadbStop, cmdMadbUninstall, cmdMadbName},
+ Children: []*cmdline.Command{cmdMadbClearData, cmdMadbExec, cmdMadbName, cmdMadbStart, cmdMadbStop, cmdMadbUninstall},
Name: "madb",
Short: "Multi-device Android Debug Bridge",
Long: `
@@ -95,6 +96,7 @@
Type deviceType
Qualifiers []string
Nickname string
+ Index int
}
// Returns the display name which is intended to be used as the console output prefix.
@@ -116,7 +118,7 @@
nsm, err := readNicknameSerialMap(nicknameFile)
if err != nil {
- fmt.Fprintln(os.Stderr, "Warning: Could not read the nickname file.")
+ return nil, err
}
return parseDevicesOutput(output, nsm)
@@ -135,17 +137,18 @@
}
// Iterate over all the device serial numbers, starting from the second line.
- for _, line := range lines[1:] {
+ for i, line := range lines[1:] {
fields := strings.Fields(line)
if len(fields) <= 1 || fields[1] == "offline" {
continue
}
- // Fill in the device serial and all the qualifiers.
+ // Fill in the device serial, all the qualifiers, and the device index.
d := device{
Serial: fields[0],
Qualifiers: fields[2:],
+ Index: i + 1,
}
// Determine whether this device is an emulator or a real device.
@@ -191,7 +194,10 @@
return nil, err
}
- filtered := filterSpecifiedDevices(allDevices)
+ filtered, err := filterSpecifiedDevices(allDevices)
+ if err != nil {
+ return nil, err
+ }
if len(filtered) == 0 {
return nil, fmt.Errorf("No devices matching the device specifiers.")
@@ -200,21 +206,42 @@
return filtered, nil
}
-func filterSpecifiedDevices(devices []device) []device {
+type deviceSpec struct {
+ index int
+ token string
+}
+
+func filterSpecifiedDevices(devices []device) ([]device, error) {
// If no device specifier flags are set, run on all devices and emulators.
if noDevicesSpecified() {
- return devices
+ return devices, nil
}
result := make([]device, 0, len(devices))
+ var specs = []deviceSpec{}
+ if devicesFlag != "" {
+ tokens := strings.Split(devicesFlag, ",")
+ for _, token := range tokens {
+ if strings.HasPrefix(token, "@") {
+ index, err := strconv.Atoi(token[1:])
+ if err != nil || index <= 0 {
+ return nil, fmt.Errorf("Invalid device specifier %q. '@' sign must be followed by a numeric device index starting from 1.", token)
+ }
+ specs = append(specs, deviceSpec{index, ""})
+ } else {
+ specs = append(specs, deviceSpec{0, token})
+ }
+ }
+ }
+
for _, d := range devices {
- if shouldIncludeDevice(d) {
+ if shouldIncludeDevice(d, specs) {
result = append(result, d)
}
}
- return result
+ return result, nil
}
func noDevicesSpecified() bool {
@@ -223,7 +250,7 @@
devicesFlag == ""
}
-func shouldIncludeDevice(d device) bool {
+func shouldIncludeDevice(d device, specs []deviceSpec) bool {
if allDevicesFlag && d.Type == realDevice {
return true
}
@@ -232,19 +259,25 @@
return true
}
- tokens := strings.Split(devicesFlag, ",")
- for _, token := range tokens {
+ for _, spec := range specs {
// Ignore empty tokens
- if token == "" {
+ if spec.index == 0 && spec.token == "" {
continue
}
- if d.Serial == token || d.Nickname == token {
+ if spec.index > 0 {
+ if d.Index == spec.index {
+ return true
+ }
+ continue
+ }
+
+ if d.Serial == spec.token || d.Nickname == spec.token {
return true
}
for _, qualifier := range d.Qualifiers {
- if qualifier == token {
+ if qualifier == spec.token {
return true
}
}
diff --git a/madb/madb_test.go b/madb/madb_test.go
index 261c592..6c4ec79 100644
--- a/madb/madb_test.go
+++ b/madb/madb_test.go
@@ -43,12 +43,14 @@
Type: realDevice,
Qualifiers: []string{"usb:3-3.4.3", "product:bullhead", "model:Nexus_5X", "device:bullhead"},
Nickname: "",
+ Index: 1,
},
device{
Serial: "emulator-5554",
Type: emulator,
Qualifiers: []string{"product:sdk_phone_armv7", "model:sdk_phone_armv7", "device:generic"},
Nickname: "",
+ Index: 2,
},
}
@@ -86,6 +88,7 @@
Type: realDevice,
Qualifiers: []string{"product:sdk_phone_armv7", "model:sdk_phone_armv7", "device:generic"},
Nickname: "",
+ Index: 2,
},
}
@@ -116,12 +119,14 @@
Type: realDevice,
Qualifiers: []string{"usb:3-3.4.3", "product:bullhead", "model:Nexus_5X", "device:bullhead"},
Nickname: "MyPhone",
+ Index: 1,
},
device{
Serial: "emulator-5554",
Type: emulator,
Qualifiers: []string{"product:sdk_phone_armv7", "model:sdk_phone_armv7", "device:generic"},
Nickname: "ARMv7",
+ Index: 2,
},
}
@@ -137,6 +142,7 @@
Type: realDevice,
Qualifiers: []string{"usb:3-3.4.3", "product:bullhead", "model:Nexus_5X", "device:bullhead"},
Nickname: "MyPhone",
+ Index: 1,
}
d2 := device{
@@ -144,6 +150,7 @@
Type: realDevice,
Qualifiers: []string{"usb:3-3.4.1", "product:volantisg", "model:Nexus_9", "device:flounder_lte"},
Nickname: "",
+ Index: 2,
}
e1 := device{
@@ -151,6 +158,7 @@
Type: emulator,
Qualifiers: []string{"product:sdk_phone_armv7", "model:sdk_phone_armv7", "device:generic"},
Nickname: "ARMv7",
+ Index: 3,
}
d3 := device{
@@ -158,6 +166,7 @@
Type: realDevice,
Qualifiers: []string{"usb:3-3.3", "product:bullhead", "model:Nexus_5X", "device:bullhead"},
Nickname: "SecondPhone",
+ Index: 4,
}
e2 := device{
@@ -165,6 +174,7 @@
Type: emulator,
Qualifiers: []string{"product:sdk_phone_armv7", "model:sdk_phone_armv7", "device:generic"},
Nickname: "",
+ Index: 5,
}
allDevices := []device{d1, d2, e1, d3, e2}
@@ -185,8 +195,10 @@
{deviceFlags{false, true, ""}, []device{e1, e2}}, // Only -e is specified
{deviceFlags{false, false, "device:bullhead"}, []device{d1, d3}}, // Device qualifier
{deviceFlags{false, false, "ARMv7,SecondPhone"}, []device{e1, d3}}, // Nicknames
+ {deviceFlags{false, false, "@2,@4"}, []device{d2, d3}}, // Device Indices
{deviceFlags{true, false, "ARMv7"}, []device{d1, d2, e1, d3}}, // Combinations
{deviceFlags{false, true, "model:Nexus_9"}, []device{d2, e1, e2}}, // Combinations
+ {deviceFlags{false, false, "@1,SecondPhone"}, []device{d1, d3}}, // Combinations
}
for i, testCase := range testCases {
@@ -194,7 +206,12 @@
allEmulatorsFlag = testCase.flags.allEmulators
devicesFlag = testCase.flags.devices
- if got := filterSpecifiedDevices(allDevices); !reflect.DeepEqual(got, testCase.want) {
+ got, err := filterSpecifiedDevices(allDevices)
+ if err != nil {
+ t.Fatalf(err.Error())
+ }
+
+ if !reflect.DeepEqual(got, testCase.want) {
t.Fatalf("unmatched results for testCases[%v]: got %v, want %v", i, got, testCase.want)
}
}
diff --git a/madb/name.go b/madb/name.go
index 8b2542d..b5fc2b4 100644
--- a/madb/name.go
+++ b/madb/name.go
@@ -5,12 +5,11 @@
package main
import (
- "bufio"
+ "encoding/json"
"fmt"
"os"
"path/filepath"
"regexp"
- "strings"
"v.io/x/lib/cmdline"
)
@@ -22,6 +21,8 @@
Long: `
Manages device nicknames, which are meant to be more human-friendly compared to
the device serials provided by adb tool.
+
+NOTE: Device specifier flags (-d, -e, -n) are ignored in all 'madb name' commands.
`,
}
@@ -224,20 +225,26 @@
f, err := os.Open(filename)
if err != nil {
+ // Nickname file may not exist when there are no nicknames assigned, and it is not an error.
+ if os.IsNotExist(err) {
+ return result, nil
+ }
+
return nil, err
}
defer f.Close()
- // TODO(youngseokyoon): use encoding/json for serialization and deserialization.
- scanner := bufio.NewScanner(f)
- for scanner.Scan() {
- line := scanner.Text()
- fields := strings.Fields(line)
- if len(fields) == 2 {
- result[fields[0]] = fields[1]
- } else {
- return nil, fmt.Errorf("Unexpected number of columns in the nickname file.")
+ decoder := json.NewDecoder(f)
+
+ // Decoding might fail when the nickname file is somehow corrupted, or when the schema is updated.
+ // In such cases, move on after resetting the cache file instead of exiting the app.
+ if err := decoder.Decode(&result); err != nil {
+ fmt.Fprintf(os.Stderr, "WARNING: Could not decode the nickname file: %q. Resetting the file.\n", err)
+ if err := os.Remove(f.Name()); err != nil {
+ return nil, err
}
+
+ return make(map[string]string), nil
}
return result, nil
@@ -252,11 +259,8 @@
}
defer f.Close()
- for nickname, serial := range nsm {
- fmt.Fprintln(f, nickname, serial)
- }
-
- return nil
+ encoder := json.NewEncoder(f)
+ return encoder.Encode(nsm)
}
// runnerFuncWithFilepath is an adapter that turns the madb name subcommand functions into cmdline.Runners.
diff --git a/madb/name_test.go b/madb/name_test.go
index 31480f2..9a39c27 100644
--- a/madb/name_test.go
+++ b/madb/name_test.go
@@ -5,7 +5,6 @@
package main
import (
- "fmt"
"os"
"reflect"
"testing"
@@ -177,55 +176,3 @@
}
}
}
-
-func TestReadNicknameSerialMap(t *testing.T) {
- filename := tempFilename(t)
- defer os.Remove(filename)
-
- f, err := os.Create(filename)
- if err != nil {
- t.Fatal(err)
- }
- fmt.Fprintln(f, "PHONE1 SERIAL1")
- fmt.Fprintln(f, "PHONE2 SERIAL2")
- fmt.Fprintln(f, "PHONE3 SERIAL3")
- f.Close()
-
- var got map[string]string
- if got, err = readNicknameSerialMap(filename); err != nil {
- t.Fatal(err)
- }
- want := map[string]string{
- "PHONE1": "SERIAL1",
- "PHONE2": "SERIAL2",
- "PHONE3": "SERIAL3",
- }
-
- if !reflect.DeepEqual(got, want) {
- t.Fatalf("unmatched results: got %v, want %v", got, want)
- }
-}
-
-func TestWriteNicknameSerialMap(t *testing.T) {
- filename := tempFilename(t)
- defer os.Remove(filename)
-
- want := map[string]string{
- "PHONE1": "SERIAL1",
- "PHONE2": "SERIAL2",
- "PHONE3": "SERIAL3",
- }
-
- if err := writeNicknameSerialMap(want, filename); err != nil {
- t.Fatalf("could not write the map to file: %v", err)
- }
-
- got, err := readNicknameSerialMap(filename)
- if err != nil {
- t.Fatal(err)
- }
-
- if !reflect.DeepEqual(got, want) {
- t.Fatalf("unmatched results: got %v, want %v", got, want)
- }
-}
diff --git a/tracify/doc.go b/tracify/doc.go
new file mode 100644
index 0000000..281d163
--- /dev/null
+++ b/tracify/doc.go
@@ -0,0 +1,26 @@
+// 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.
+
+// This file was auto-generated via go generate.
+// DO NOT UPDATE MANUALLY
+
+/*
+tracify adds vtrace annotations to all functions in the given packages that have
+a context as the first argument.
+
+TODO(mattr): We will eventually support various options like excluding certain
+functions or including specific information in the span name.
+
+Usage:
+ tracify [flags] [-t] [packages]
+
+The global flags are:
+ -metadata=<just specify -metadata to activate>
+ Displays metadata for the program and exits.
+ -t=false
+ include transitive dependencies of named packages.
+ -time=false
+ Dump timing information to stderr before exiting the program.
+*/
+package main
diff --git a/tracify/injector.go b/tracify/injector.go
new file mode 100644
index 0000000..21d0476
--- /dev/null
+++ b/tracify/injector.go
@@ -0,0 +1,72 @@
+// 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 (
+ "bytes"
+ "go/token"
+ "io"
+ "io/ioutil"
+ "os"
+ "text/template"
+)
+
+// injectors allow you to rewrite a file adding content at points specified in the source files
+// address space.
+type injector struct {
+ read int
+ r io.Reader
+ w bytes.Buffer
+ fname string
+}
+
+func newInjector(fname string) (*injector, error) {
+ var err error
+ i := &injector{fname: fname}
+ i.r, err = os.Open(fname)
+ return i, err
+}
+
+func (i *injector) copyTo(p token.Position) error {
+ toread := p.Offset + 1 - i.read
+ i.read += toread
+ _, err := io.CopyN(&i.w, i.r, int64(toread))
+ return err
+}
+
+func (i *injector) inject(p token.Position, content string) error {
+ if err := i.copyTo(p); err != nil {
+ return err
+ }
+ _, err := i.w.Write([]byte(content))
+ return err
+}
+
+func (i *injector) format() error {
+ if _, err := io.Copy(&i.w, i.r); err != nil {
+ return err
+ }
+ //out, err := format.Source(i.w.Bytes())
+ //if err != nil {
+ // return err
+ //}
+ out := i.w.Bytes()
+ f, err := os.Create(i.fname)
+ if err != nil {
+ return err
+ }
+ stat, err := f.Stat()
+ if err != nil {
+ return err
+ }
+ return ioutil.WriteFile(i.fname, out, stat.Mode())
+}
+
+func (i *injector) execute(p token.Position, t *template.Template, data interface{}) error {
+ if err := i.copyTo(p); err != nil {
+ return err
+ }
+ return t.Execute(&i.w, data)
+}
diff --git a/tracify/tracify.go b/tracify/tracify.go
new file mode 100644
index 0000000..84b72aa
--- /dev/null
+++ b/tracify/tracify.go
@@ -0,0 +1,314 @@
+// 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.
+
+// The following enables go generate to generate the doc.go file.
+//go:generate go run $JIRI_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
+
+package main
+
+import (
+ "bytes"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/format"
+ "go/parser"
+ "go/token"
+ "io"
+ "os/exec"
+ "strings"
+
+ "text/template"
+ "v.io/x/lib/cmdline"
+ "v.io/x/lib/envvar"
+)
+
+var skipPackages = map[string]bool{
+ "v.io/v23/vtrace": true,
+ "v.io/v23/verror": true,
+ "v.io/x/ref/runtime/internal/vtrace": true,
+}
+
+func main() {
+ cmdline.Main(cmdTracify)
+}
+
+var (
+ transitive = flag.Bool("t", false, "include transitive dependencies of named packages.")
+)
+
+var cmdTracify = &cmdline.Command{
+ Name: "tracify",
+ Short: "Add vtrace annotations to functions in the specified packages.",
+ Long: `
+tracify adds vtrace annotations to all functions in the given packages that
+have a context as the first argument.
+
+TODO(mattr): We will eventually support various options like excluding certain functions
+or including specific information in the span name.
+`,
+ ArgsName: "[-t] [packages]",
+ Runner: cmdline.RunnerFunc(tracify),
+}
+
+// tracify adds vtrace spans to functions in the packages defined by args.
+func tracify(env *cmdline.Env, args []string) error {
+ pkgs, err := readPackages(env, args)
+ if err != nil {
+ return err
+ }
+ if *transitive {
+ tPkgs := map[string]*build.Package{}
+ for _, pkg := range pkgs {
+ if err := addTransitive(tPkgs, pkg, true); err != nil {
+ return err
+ }
+ }
+ pkgs = tPkgs
+ }
+ for _, pkg := range pkgs {
+ if pkg != nil {
+ if err := processPackage(pkg); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+// processPackage processes a build package, rewriting any file in the package
+// to include vtrace annotations.
+func processPackage(pkg *build.Package) error {
+ fset := token.NewFileSet()
+ pkgs, err := parser.ParseDir(fset, pkg.Dir, nil, parser.ParseComments)
+ if err != nil {
+ return err
+ }
+ for _, p := range pkgs {
+ for fname, f := range p.Files {
+ processFile(fset, fname, f)
+ }
+ }
+ return nil
+}
+
+var vtraceTpl = template.Must(template.New("vtrace").Parse(`
+ {{.CtxName}}, vspan := {{.VtraceName}}.WithNewSpan({{.CtxName}}, "{{.FuncName}}")
+ defer vspan.Finish()
+`))
+
+type decl struct {
+ pos token.Position
+ CtxName string
+ FuncName string
+ VtraceName string
+}
+
+// processFile Processes a single source file, rewriting it to include vtrace
+// spans where necessary.
+func processFile(fset *token.FileSet, fname string, f *ast.File) error {
+ vtraceName := ""
+ for _, i := range f.Imports {
+ if i.Path.Value == "\"v.io/v23/vtrace\"" {
+ if i.Name == nil {
+ vtraceName = "vtrace"
+ } else {
+ vtraceName = i.Name.Name
+ }
+ }
+ }
+
+ decls := []decl{}
+ args := translateTypes(fset, f.Imports, []string{"*context.T"})
+ for _, d := range f.Decls {
+ if fd, ok := d.(*ast.FuncDecl); ok {
+ matches, names := checkParams(fset, fd.Type, args)
+ if !matches || len(names) == 0 || names[0] == "_" {
+ continue
+ }
+ decls = append(decls, decl{
+ pos: fset.Position(fd.Body.Lbrace),
+ CtxName: names[0],
+ FuncName: fd.Name.Name,
+ })
+ }
+ }
+
+ if len(decls) > 0 {
+ inj, err := newInjector(fname)
+ if err != nil {
+ return err
+ }
+ if vtraceName == "" {
+ if err := inj.inject(fset.Position(f.Name.End()), "\nimport \"v.io/v23/vtrace\"\n"); err != nil {
+ return err
+ }
+ vtraceName = "vtrace"
+ }
+ for _, d := range decls {
+ d.VtraceName = vtraceName
+ if err := inj.execute(d.pos, vtraceTpl, d); err != nil {
+ return err
+ }
+ }
+ if err := inj.format(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// readPackages resolves the user-supplied package patterns to a list of actual packages.
+// We just call out to 'go list' for this since there is actually a lot of subtlety
+// in resolving the patterns.
+func readPackages(env *cmdline.Env, args []string) (map[string]*build.Package, error) {
+ buf := &bytes.Buffer{}
+ opts := []string{"list", "-json"}
+ cmd := exec.Command("go", append(opts, args...)...)
+ cmd.Env = envvar.MapToSlice(env.Vars)
+ cmd.Stderr = env.Stderr
+ cmd.Stdout = buf
+ if err := cmd.Run(); err != nil {
+ return nil, fmt.Errorf("Could not list packages: %v", err)
+ }
+ dec := json.NewDecoder(buf)
+ packages := map[string]*build.Package{}
+ for {
+ var pkg build.Package
+ if err := dec.Decode(&pkg); err == io.EOF {
+ break
+ } else if err != nil {
+ return nil, err
+ }
+ packages[pkg.ImportPath] = &pkg
+ }
+ return packages, nil
+}
+
+// addTransitive adds the transitive dependencies of pkg to packages.
+func addTransitive(packages map[string]*build.Package, pkg *build.Package, alsoTest bool) error {
+ if skipPackages[pkg.ImportPath] {
+ return nil
+ }
+ if _, ok := packages[pkg.ImportPath]; ok {
+ return nil
+ }
+ packages[pkg.ImportPath] = nil
+ foundCtx := false
+ for _, dep := range pkg.Imports {
+ if dep == "v.io/v23/context" {
+ foundCtx = true
+ break
+ }
+ }
+
+ allImports := [][]string{pkg.Imports}
+ if alsoTest {
+ allImports = append(allImports, pkg.TestImports, pkg.XTestImports)
+ }
+
+ for _, imports := range allImports {
+ for _, dep := range imports {
+ if dep == "C" {
+ continue
+ }
+ depPkg, err := build.Import(dep, "", 0)
+ if err != nil {
+ return err
+ }
+ if err := addTransitive(packages, depPkg, false); err != nil {
+ return err
+ }
+ }
+ }
+ // Skip if we don't depend on context.
+ if foundCtx {
+ packages[pkg.ImportPath] = pkg
+ }
+ return nil
+}
+
+// checkParams returns true if the given function type has argument types matching
+// the strings in args.
+func checkParams(fset *token.FileSet, ftype *ast.FuncType, args []string) (bool, []string) {
+ i := 0
+ names := []string{}
+ buf := &bytes.Buffer{}
+ for _, param := range ftype.Params.List {
+ buf.Reset()
+ format.Node(buf, fset, param.Type)
+ typeStr := buf.String()
+ nnames := len(param.Names)
+ if nnames == 0 {
+ nnames = 1 //Anonymous field.
+ }
+ for n := 0; n < nnames; n++ {
+ if args[i] != typeStr {
+ return false, nil
+ }
+ if n < len(param.Names) {
+ names = append(names, param.Names[n].Name)
+ }
+ if i++; i >= len(args) {
+ return true, names
+ }
+ }
+ }
+ return false, nil
+}
+
+// translateTypes uses the declared imports to change a list of queried types to their mapped versions.
+// For example if you call:
+// translateTypes(fset, imports, "*testing.T")
+// and imports contains the import:
+// import t "testing"
+// Then we will return:
+// []string{"*t.T"}
+func translateTypes(fset *token.FileSet, imports []*ast.ImportSpec, types []string) []string {
+ namedImports := map[string]string{}
+ for _, i := range imports {
+ if i.Name != nil {
+ path := strings.Trim(i.Path.Value, "\"")
+ namedImports[path] = i.Name.Name
+ }
+ }
+ out := make([]string, len(types))
+ buf := &bytes.Buffer{}
+ for i, typ := range types {
+ out[i] = typ
+ if expr, err := parser.ParseExpr(typ); err == nil && changePackage(expr, namedImports) {
+ buf.Reset()
+ if err := format.Node(buf, fset, expr); err == nil {
+ out[i] = buf.String()
+ }
+ }
+ }
+ return out
+}
+
+// This changes the package name of a type to the mapped name.
+// For example if you pass in the expr corresponding to "*testing.T" but
+// the file has declared:
+// import t "testing"
+// then it will return the expr for "*t.T".
+// TODO(mattr): I'm not sure this catches all the cases. If we find a breakage
+// we can fix it then.
+func changePackage(expr ast.Expr, namedImports map[string]string) bool {
+ switch e := expr.(type) {
+ case *ast.StarExpr:
+ return changePackage(e.X, namedImports)
+ case *ast.SelectorExpr:
+ if id, ok := e.X.(*ast.Ident); ok {
+ if name, has := namedImports[id.Name]; has {
+ id.Name = name
+ }
+ return true
+ }
+ return false
+ default:
+ return false
+ }
+}