func TestGenerateWithRelativePaths(t *testing.T) {
	outputDir, err := ioutil.TempDir("", "thriftrw-generate-test")
	require.NoError(t, err)
	defer os.RemoveAll(outputDir)

	thriftRoot, err := os.Getwd()
	require.NoError(t, err)

	module, err := compile.Compile("testdata/thrift/structs.thrift")
	require.NoError(t, err)

	opts := []*Options{
		{
			OutputDir:     outputDir,
			PackagePrefix: "go.uber.org/thriftrw/gen",
			ThriftRoot:    "testdata",
		},
		{
			OutputDir:     "testdata",
			PackagePrefix: "go.uber.org/thriftrw/gen",
			ThriftRoot:    thriftRoot,
		},
	}

	for _, opt := range opts {
		err := Generate(module, opt)
		if assert.Error(t, err, "expected code generation with %v to fail", opt) {
			assert.Contains(t, err.Error(), "must be an absolute path")
		}
	}
}
Exemple #2
0
func TestCodeIsUpToDate(t *testing.T) {
	// This test just verifies that the generated code in testdata/ is up to
	// date. If this test failed, run 'make' in the testdata/ directory and
	// commit the changes.

	thriftRoot, err := filepath.Abs("testdata/thrift")
	require.NoError(t, err, "could not resolve absolute path to testdata/thrift")

	thriftFiles, err := filepath.Glob(thriftRoot + "/*.thrift")
	require.NoError(t, err)

	outputDir, err := ioutil.TempDir("", "thriftrw-golden-test")
	require.NoError(t, err)
	defer os.RemoveAll(outputDir)

	for _, thriftFile := range thriftFiles {
		pkgRelPath := strings.TrimSuffix(filepath.Base(thriftFile), ".thrift")
		currentPackageDir := filepath.Join("testdata", pkgRelPath)
		newPackageDir := filepath.Join(outputDir, pkgRelPath)

		currentHash, err := dirhash(currentPackageDir)
		require.NoError(t, err, "could not hash %q", currentPackageDir)

		module, err := compile.Compile(thriftFile)
		require.NoError(t, err, "failed to compile %q", thriftFile)

		err = Generate(module, &Options{
			OutputDir:     outputDir,
			PackagePrefix: "go.uber.org/thriftrw/gen/testdata",
			ThriftRoot:    thriftRoot,
			NoRecurse:     true,
		})
		require.NoError(t, err, "failed to generate code for %q", thriftFile)

		newHash, err := dirhash(newPackageDir)
		require.NoError(t, err, "could not hash %q", newPackageDir)

		if newHash != currentHash {
			// TODO(abg): Diff the two directories?
			t.Fatalf(
				"Generated code for %q is out of date. "+
					"Please run 'make' in gen/testdata.", thriftFile)
		}
	}
}
Exemple #3
0
func main() {
	log.SetFlags(0) // don't include timestamps, etc. in the output

	var opts options

	parser := flags.NewParser(&opts, flags.Default)
	parser.Usage = "[OPTIONS] FILE"

	args, err := parser.Parse()
	if err != nil {
		return // message already printed by go-flags
	}

	if opts.DisplayVersion {
		fmt.Printf("thriftrw v%s\n", version.Version)
		os.Exit(0)
	}

	if len(args) != 1 {
		parser.WriteHelp(os.Stdout)
		os.Exit(1)
	}

	inputFile := args[0]
	if _, err := os.Stat(inputFile); err != nil {
		if os.IsNotExist(err) {
			log.Fatalf("File %q does not exist: %v", inputFile, err)
		}
		log.Fatalf("Could not stat file %q: %v", inputFile, err)
	}

	gopts := opts.GOpts
	if len(gopts.OutputDirectory) == 0 {
		gopts.OutputDirectory = "."
	}
	gopts.OutputDirectory, err = filepath.Abs(gopts.OutputDirectory)
	if err != nil {
		log.Fatalf("Unable to resolve absolute path for %q: %v", gopts.OutputDirectory, err)
	}

	if gopts.PackagePrefix == "" {
		gopts.PackagePrefix, err = determinePackagePrefix(gopts.OutputDirectory)
		if err != nil {
			log.Fatalf(
				"Could not determine a package prefix automatically: %v\n"+
					"A package prefix is required to use correct import paths in the generated code.\n"+
					"Use the --pkg-prefix option to provide a package prefix manually.", err)
		}
	}

	module, err := compile.Compile(inputFile)
	if err != nil {
		// TODO(abg): For nested compile errors, split causal chain across
		// multiple lines.
		log.Fatalf("Failed to compile %q: %v", inputFile, err)
	}

	if gopts.ThriftRoot == "" {
		gopts.ThriftRoot, err = findCommonAncestor(module)
		if err != nil {
			log.Fatalf(
				"Could not find a common parent directory for %q and the Thrift files "+
					"imported by it.\nThis directory is required to generate a consistent "+
					"hierarchy for generated packages.\nUse the --thrift-root option to "+
					"provide this path.", err)
		}
	} else {
		gopts.ThriftRoot, err = filepath.Abs(gopts.ThriftRoot)
		if err != nil {
			log.Fatalf("Unable to resolve absolute path for %q: %v", gopts.ThriftRoot, err)
		}
		if err := verifyAncestry(module, gopts.ThriftRoot); err != nil {
			log.Fatalf(
				"An included Thrift file is not contained in the %q directory tree: %v",
				gopts.ThriftRoot, err)
		}
	}

	pluginHandle, err := gopts.Plugins.Handle()
	if err != nil {
		log.Fatalf("Failed to initialize plugins: %v", err)
	}

	if gopts.GeneratePluginAPI {
		pluginHandle = append(pluginHandle, pluginapigen.Handle)
	}

	defer pluginHandle.Close()

	generatorOptions := gen.Options{
		OutputDir:      gopts.OutputDirectory,
		PackagePrefix:  gopts.PackagePrefix,
		ThriftRoot:     gopts.ThriftRoot,
		NoRecurse:      gopts.NoRecurse,
		NoVersionCheck: gopts.NoVersionCheck,
		Plugin:         pluginHandle,
	}
	if err := gen.Generate(module, &generatorOptions); err != nil {
		log.Fatalf("Failed to generate code: %v", err)
	}
}