Skip to content

Commit

Permalink
Merge pull request #171 from uber/zw.idl-registry
Browse files Browse the repository at this point in the history
Add IDL registry repository
  • Loading branch information
zhenghuiwang committed Jul 28, 2017
2 parents b80f771 + 4669d3b commit d9f75ae
Show file tree
Hide file tree
Showing 10 changed files with 538 additions and 20 deletions.
2 changes: 1 addition & 1 deletion backend/repository/config.go
Expand Up @@ -60,7 +60,7 @@ type EndpointConfig struct {
Type ProtocolType `json:"endpointType"`
HandleID string `json:"handleId"`
ThriftFile string `json:"thriftFile"`
ThriftFileSha string `json:"thriftFileSha",omitempty`
ThriftFileSha string `json:"thriftFileSha,omitempty"`
ThriftMethodName string `json:"thriftMethodName"`
WorkflowType string `json:"workflowType"`
ClientID string `json:"clientID"`
Expand Down
19 changes: 0 additions & 19 deletions backend/repository/data/gateway_config_expected.json
Expand Up @@ -16,7 +16,6 @@
"endpointType": "http",
"handleId": "argNotStruct",
"thriftFile": "endpoints/bar/bar.thrift",
"thriftFileSha": "",
"thriftMethodName": "Bar::argNotStruct",
"workflowType": "httpClient",
"clientID": "bar",
Expand All @@ -31,7 +30,6 @@
"endpointType": "http",
"handleId": "argWithHeaders",
"thriftFile": "endpoints/bar/bar.thrift",
"thriftFileSha": "",
"thriftMethodName": "Bar::argWithHeaders",
"workflowType": "httpClient",
"clientID": "bar",
Expand All @@ -46,7 +44,6 @@
"endpointType": "http",
"handleId": "argWithManyQueryParams",
"thriftFile": "endpoints/bar/bar.thrift",
"thriftFileSha": "",
"thriftMethodName": "Bar::argWithManyQueryParams",
"workflowType": "httpClient",
"clientID": "bar",
Expand All @@ -61,7 +58,6 @@
"endpointType": "http",
"handleId": "argWithNestedQueryParams",
"thriftFile": "endpoints/bar/bar.thrift",
"thriftFileSha": "",
"thriftMethodName": "Bar::argWithNestedQueryParams",
"workflowType": "httpClient",
"clientID": "bar",
Expand All @@ -76,7 +72,6 @@
"endpointType": "http",
"handleId": "argWithParams",
"thriftFile": "endpoints/bar/bar.thrift",
"thriftFileSha": "",
"thriftMethodName": "Bar::argWithParams",
"workflowType": "httpClient",
"clientID": "bar",
Expand All @@ -91,7 +86,6 @@
"endpointType": "http",
"handleId": "argWithQueryHeader",
"thriftFile": "endpoints/bar/bar.thrift",
"thriftFileSha": "",
"thriftMethodName": "Bar::argWithQueryHeader",
"workflowType": "httpClient",
"clientID": "bar",
Expand All @@ -106,7 +100,6 @@
"endpointType": "http",
"handleId": "argWithQueryParams",
"thriftFile": "endpoints/bar/bar.thrift",
"thriftFileSha": "",
"thriftMethodName": "Bar::argWithQueryParams",
"workflowType": "httpClient",
"clientID": "bar",
Expand All @@ -121,7 +114,6 @@
"endpointType": "http",
"handleId": "missingArg",
"thriftFile": "endpoints/bar/bar.thrift",
"thriftFileSha": "",
"thriftMethodName": "Bar::missingArg",
"workflowType": "httpClient",
"clientID": "bar",
Expand All @@ -136,7 +128,6 @@
"endpointType": "http",
"handleId": "noRequest",
"thriftFile": "endpoints/bar/bar.thrift",
"thriftFileSha": "",
"thriftMethodName": "Bar::noRequest",
"workflowType": "httpClient",
"clientID": "bar",
Expand All @@ -151,7 +142,6 @@
"endpointType": "http",
"handleId": "normal",
"thriftFile": "endpoints/bar/bar.thrift",
"thriftFileSha": "",
"thriftMethodName": "Bar::normal",
"workflowType": "httpClient",
"clientID": "bar",
Expand All @@ -166,7 +156,6 @@
"endpointType": "http",
"handleId": "tooManyArgs",
"thriftFile": "endpoints/bar/bar.thrift",
"thriftFileSha": "",
"thriftMethodName": "Bar::tooManyArgs",
"workflowType": "httpClient",
"clientID": "bar",
Expand All @@ -181,7 +170,6 @@
"endpointType": "http",
"handleId": "call",
"thriftFile": "endpoints/baz/baz.thrift",
"thriftFileSha": "",
"thriftMethodName": "SimpleService::call",
"workflowType": "tchannelClient",
"clientID": "baz",
Expand All @@ -196,7 +184,6 @@
"endpointType": "http",
"handleId": "compare",
"thriftFile": "endpoints/baz/baz.thrift",
"thriftFileSha": "",
"thriftMethodName": "SimpleService::compare",
"workflowType": "tchannelClient",
"clientID": "baz",
Expand All @@ -211,7 +198,6 @@
"endpointType": "http",
"handleId": "ping",
"thriftFile": "endpoints/baz/baz.thrift",
"thriftFileSha": "",
"thriftMethodName": "SimpleService::ping",
"workflowType": "tchannelClient",
"clientID": "baz",
Expand All @@ -226,7 +212,6 @@
"endpointType": "http",
"handleId": "sillyNoop",
"thriftFile": "endpoints/baz/baz.thrift",
"thriftFileSha": "",
"thriftMethodName": "SimpleService::sillyNoop",
"workflowType": "tchannelClient",
"clientID": "baz",
Expand All @@ -241,7 +226,6 @@
"endpointType": "tchannel",
"handleId": "call",
"thriftFile": "endpoints/tchannel/baz/baz.thrift",
"thriftFileSha": "",
"thriftMethodName": "SimpleService::Call",
"workflowType": "custom",
"clientID": "",
Expand All @@ -256,7 +240,6 @@
"endpointType": "http",
"handleId": "saveContacts",
"thriftFile": "endpoints/contacts/contacts.thrift",
"thriftFileSha": "",
"thriftMethodName": "Contacts::saveContacts",
"workflowType": "custom",
"clientID": "",
Expand All @@ -271,7 +254,6 @@
"endpointType": "http",
"handleId": "addCredentials",
"thriftFile": "endpoints/googlenow/googlenow.thrift",
"thriftFileSha": "",
"thriftMethodName": "GoogleNow::addCredentials",
"workflowType": "httpClient",
"clientID": "google-now",
Expand All @@ -286,7 +268,6 @@
"endpointType": "http",
"handleId": "checkCredentials",
"thriftFile": "endpoints/googlenow/googlenow.thrift",
"thriftFileSha": "",
"thriftMethodName": "GoogleNow::checkCredentials",
"workflowType": "httpClient",
"clientID": "google-now",
Expand Down
147 changes: 147 additions & 0 deletions backend/repository/idl_registry.go
@@ -0,0 +1,147 @@
// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package repository

import (
"io/ioutil"
"path/filepath"
"sync"

"github.com/pkg/errors"
)

// IDLRegistry provides the content and version of a thrift file.
type IDLRegistry interface {
// RootDir returns the path of the root directory for the registry.
RootDir() string
// ThriftRootDir returns the relative path of the thrift root directory.
ThriftRootDir() string
// Updates the IDLRegistry to sync with remote source.
Update() error
// Returns the file version or content of a thrift file.
ThriftMeta(path string, needFileContent bool) (*ThriftMeta, error)
}

type idlRegistry struct {
idlDir string
repo *Repository
// Map from thrift file to its meta, which is updated when underlying Repository being updated.
metaMap map[string]*ThriftMeta
// Lock for metaMap.
lock sync.RWMutex
}

const metaJSONFile = "meta.json"

// NewIDLRegistry assumes all thrift files are located under the dir of
// relative path `idlDirRel` of a single repository and there is a
// meta.json file containing all version information of thrift files.
func NewIDLRegistry(idlDirRel string, repo *Repository) (IDLRegistry, error) {
newMap, err := allFileMeta(filepath.Join(repo.LocalDir(), metaJSONFile))
if err != nil {
return nil, err
}
return &idlRegistry{
idlDir: idlDirRel,
repo: repo,
metaMap: newMap,
}, nil
}

// RootDir returns the path of the root directory for the registry.
func (reg *idlRegistry) RootDir() string {
return reg.repo.LocalDir()
}

// ThriftRootDir returns the relative path of the thrift root directory.
func (reg *idlRegistry) ThriftRootDir() string {
return reg.idlDir
}

// IDLRegistryFile returns the content and meta data of a file in IDL-registry.
func (reg *idlRegistry) ThriftMeta(path string, needFileContent bool) (*ThriftMeta, error) {
if err := reg.Update(); err != nil {
return nil, err
}
reg.lock.RLock()
defer reg.lock.RUnlock()
meta, ok := reg.metaMap[path]
if !ok {
return nil, errors.Errorf("failed to find file %q", path)
}
if !needFileContent {
return meta, nil
}
file := filepath.Join(reg.repo.LocalDir(), reg.idlDir, path)
content, err := ioutil.ReadFile(file)
if err != nil {
return nil, errors.Wrapf(err, "faile to read thrift file content %q", path)
}
return &ThriftMeta{
Path: path,
Version: meta.Version,
Content: string(content),
}, nil
}

// Types used to parse meta.json file under idlRegistry repository.
type idlMetaJSON struct {
// Remote name -> Remote meta.
Remotes map[string]remoteMeta `json:"remotes"`
}

type remoteMeta struct {
// File subpath -> SHASureg.
SHASums map[string]string `json:"shasums"`
}

func allFileMeta(metaJSONPath string) (map[string]*ThriftMeta, error) {
var metaJSONContent idlMetaJSON
if err := readJSONFile(metaJSONPath, &metaJSONContent); err != nil {
return nil, errors.Wrap(err, "failed to read meta.json of IDL registry")
}
meta := make(map[string]*ThriftMeta, len(metaJSONContent.Remotes))
for remote, rMeta := range metaJSONContent.Remotes {
for subpath, sha := range rMeta.SHASums {
path := filepath.Join(remote, subpath)
meta[path] = &ThriftMeta{
Path: path,
Version: sha,
}
}
}
return meta, nil
}

// Update updates the repository.
func (reg *idlRegistry) Update() error {
if !reg.repo.Update() {
return nil
}
newMap, err := allFileMeta(filepath.Join(reg.repo.LocalDir(), metaJSONFile))
if err != nil {
return err
}
reg.lock.Lock()
defer reg.lock.Unlock()
reg.metaMap = newMap
return nil
}

0 comments on commit d9f75ae

Please sign in to comment.