compiler/protogen: allow specifying the package name with M flags

When using the M flags (which is functionally a mapping of
filenames to Go package paths), provide the user the ability to also
specify the package name by delimiting the package path with a ";".

Example usage:
	Mpath/to/foo.proto=path/to/foo_go_proto;foopb

This uses the exact same syntax as the go_package option where a
";" delimiter can be used to specify a package name.
It brings the M flags and the go_package option closer in behavior.

Change-Id: I98e1fbb66ec2f1b70b4143b305355e5ab35ea198
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/223819
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/compiler/protogen/protogen.go b/compiler/protogen/protogen.go
index de9cb8b..5cd2a80 100644
--- a/compiler/protogen/protogen.go
+++ b/compiler/protogen/protogen.go
@@ -191,6 +191,14 @@
 			}
 		default:
 			if param[0] == 'M' {
+				if i := strings.Index(value, ";"); i >= 0 {
+					pkgName := GoPackageName(value[i+1:])
+					if otherName, ok := packageNames[param[1:]]; ok && pkgName != otherName {
+						return nil, fmt.Errorf("inconsistent package names for %q: %q != %q", value[:i], pkgName, otherName)
+					}
+					packageNames[param[1:]] = pkgName
+					value = value[:i]
+				}
 				importPaths[param[1:]] = GoImportPath(value)
 				mfiles[param[1:]] = true
 				continue
@@ -261,6 +269,8 @@
 		packageName, importPath := goPackageOption(fdesc)
 		defaultPackageName := packageNameForImportPath[importPaths[filename]]
 		switch {
+		case packageNames[filename] != "":
+			// A package name specified by the "M" command-line argument.
 		case packageName != "":
 			// TODO: For the "M" command-line argument, this means that the
 			// package name can be derived from the go_package option.
diff --git a/compiler/protogen/protogen_test.go b/compiler/protogen/protogen_test.go
index 1f7b75c..0967516 100644
--- a/compiler/protogen/protogen_test.go
+++ b/compiler/protogen/protogen_test.go
@@ -142,6 +142,15 @@
 			wantFilenamePrefix: "golang.org/x/foo/filename",
 		},
 		{
+			desc:               "command line sets import path for a file with package name specified",
+			parameter:          "Mdir/filename.proto=golang.org/x/bar;bar",
+			goPackageOption:    "golang.org/x/foo",
+			generate:           true,
+			wantPackageName:    "bar",
+			wantImportPath:     "golang.org/x/bar",
+			wantFilenamePrefix: "golang.org/x/foo/filename",
+		},
+		{
 			desc:               "import_path parameter sets import path of generated files",
 			parameter:          "import_path=golang.org/x/bar",
 			goPackageOption:    "golang.org/x/foo",