Skip to content

Commit

Permalink
Implemented enhancement CiscoDevNet#1007 (PEP440 versioning)
Browse files Browse the repository at this point in the history
  • Loading branch information
ygorelik committed Jan 11, 2021
1 parent b68177b commit 0fdd9fe
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 51 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* Develop utility function to clone Entity instance ([#967](https://github.com/CiscoDevNet/ydk-gen/issues/967))
* Go CodecService fails to encode leaf-list data ([#968](https://github.com/CiscoDevNet/ydk-gen/issues/968))
* Developed script install_ydk, which allows to install YDK from source in one CLI command
* Version numbers in bundle resolver to comply with PEP 440 ([#1007](https://github.com/CiscoDevNet/ydk-gen/issues/1007))
* Added support for CentOS/RHEL-8 and Ubuntu-20.04 (focal) ([#1019](https://github.com/CiscoDevNet/ydk-gen/issues/1019))

#### Resolved GitHub issues
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -312,16 +312,18 @@ The first step in using ydk-gen is either using one of the already built [bundle

Construct a bundle profile file, such as [```ietf_0_1_1.json```](profiles/bundles/ietf_0_1_1.json) and specify its dependencies.

A sample bundle profile file is described below. The file is in a JSON format. Specify the `"name"` of your bundle, the `"version"` of the bundle and the `"core_version"`, which refers to [the version](https://github.com/CiscoDevNet/ydk-gen/releases) of the ydk core package you want to use with this bundle. The `"name"` of the bundle here is especially important as this will form part of the installation path of the bundle.
A sample bundle profile file is described below. The file is in a JSON format. The profile must define the `"name"`, `"version"` and `"description"` of the bundle, and then the `"core_version"`, which refers to [the version](https://github.com/CiscoDevNet/ydk-gen/releases) of the ydk core package that you want to use with this bundle.
The `"name"` of the bundle will form part of the installation path of the bundle.
All other attributes, like `"author"` and `"copyright"`, are optional and will not affect the bundle generation.

```
{
"name":"cisco-ios-xr",
"version": "6.5.3",
"core_version": "0.8.6",
"Author": "Cisco",
"Copyright": "Cisco",
"Description": "Cisco IOS-XR Native Models From Git",
"author": "Cisco",
"copyright": "Cisco",
"description": "Cisco IOS-XR Native Models From Git",
```

The `"models"` section of the profile describes sources of YANG models. It could contain combination of elements:
Expand Down
10 changes: 6 additions & 4 deletions profiles/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,19 @@ This part must include:
- `"name"` of the bundle; the name also used to form part of the installation path of the bundle
- `"version"` of the bundle
- `"core_version"`, which refers to the [version](https://github.com/CiscoDevNet/ydk-gen/releases) of the YDK core package.
- `"description"`, short description of the bundle

Other components of description part are optional. Here is simple example of description part:
Other components of description part are optional, they will not affect the bundle generation.
Here is simple example of description part:

```
{
"name":"cisco-ios-xr",
"version": "6.5.3",
"core_version": "0.8.4",
"Author": "Cisco",
"Copyright": "Cisco",
"Description": "Cisco IOS-XR Native Models From Git",
"author": "Cisco",
"copyright": "Cisco",
"description": "Cisco IOS-XR Native Models From Git",
```

### Bundle Components
Expand Down
6 changes: 3 additions & 3 deletions profiles/test/ydktest.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"name": "ydktest",
"version": "0.5.1",
"ydk_version":"0.5.5",
"version": "0.5.1.dev1",
"core_version": "0.8.5",
"author": "Cisco",
"copyright": "Cisco",
"description": "YDK Test Profile",
"description": "YDK Unit Test Profile",
"models": {
"file": [
"sdk/cpp/core/tests/models/ydktest-filterread@2015-11-17.yang",
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ sphinx-rtd-theme==0.1.9
GitPython==2.1.15
rstr==2.2.6
wheel==0.34.2
packaging==20.8
79 changes: 45 additions & 34 deletions ydkgen/resolver/bundle_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from collections import namedtuple, defaultdict
from .bundle_translator import translate
from ..common import YdkGenException
from packaging.version import Version, InvalidVersion


logger = logging.getLogger('ydkgen')
Expand All @@ -44,7 +45,6 @@
Remote = namedtuple('Remote', ['url', 'commitid', 'path'])
RepoDir = namedtuple('RepoDir', ['repo', 'dir'])
Bundles = namedtuple('Bundles', ['curr_bundle', 'bundles'])
Version = namedtuple('Version', ['major', 'minor', 'patch'])


def nested_defaultdict():
Expand Down Expand Up @@ -87,8 +87,16 @@ class BundleDefinition(object):

def __init__(self, data):
self._name = data['name'].replace('-', '_')
self._version = Version(*tuple(data['version'].split('.')))
self._core_version = Version(*tuple(data['core-version'].split('.')))
try:
self._version = Version(data['version'])
except InvalidVersion:
raise YdkGenException("Bundle version '%s' is not valid."
"Version format must be 'N(.N)*[{a|b|rc}N][.postN][.devN]'." % data['version'])
try:
self._core_version = Version(data['core-version'])
except InvalidVersion:
raise YdkGenException("YDK core version '%s' is not valid."
"Version format must be 'N(.N)*[{a|b|rc}N][.postN][.devN]'." % data['core_version'])
self._description = data['description'] if 'description' in data else str()
self._long_description = data['long-description'] if 'long-description' in data else str()

Expand All @@ -114,12 +122,12 @@ def core_version(self):
@property
def str_version(self):
""" Return string representation of version."""
return "%s.%s.%s" % self.version
return str(self.version)

@property
def str_core_version(self):
""" Return string representation of ydk version."""
return "%s.%s.%s" % self.core_version
return str(self.core_version)

@property
def description(self):
Expand Down Expand Up @@ -325,38 +333,15 @@ def _resolve_bundles(self, root):
elif isinstance(entry, list):
entry.append(root)
elif isinstance(uri, Local):
self._resolve_file(uri.url, root.resolved_models_dir)
_resolve_file(uri.url, root.resolved_models_dir)
for d in root.dependencies:
if d.fqn not in self.bundles:
node = Bundle(self._resolve_bundle_file(d.uri),
self.cached_models_dir, self.iskeyword)
self.bundles[d.fqn] = node
self._add_symlink(root, node)
_add_symlink(root, node)
self._resolve_bundles(node)

def _add_symlink(self, bundle, dependency):
source = dependency.resolved_models_dir
link_name = os.path.basename(source)
link_name = os.path.join(bundle.resolved_models_dir, link_name)
os.symlink(source, link_name)

def _clone_repo(self, url, suffix=''):
tmp_dir = tempfile.mkdtemp(suffix)
repo = Repo.clone_from(url, tmp_dir)
return RepoDir(repo, tmp_dir)

def _resolve_file(self, src, dst_dir, rename=''):
""" Resolve file from src to dst directory.
"""
fname = os.path.basename(src)
logger.debug('Resolving file {} --> {}'.format(fname, dst_dir))
if rename == '':
dst = os.path.join(dst_dir, fname)
else:
dst = os.path.join(dst_dir, rename)
copy(src, dst)
return dst

def _translate(self, description_file):
""" Try to translate description file to bundle description file syntax.
"""
Expand All @@ -375,23 +360,49 @@ def _resolve_bundle_file(self, uri):
if isinstance(uri, Local):
src = uri.url
else:
repo, tmp_dir = self._clone_repo(uri.url, suffix='.bundle')
repo, tmp_dir = _clone_repo(uri.url, suffix='.bundle')
repo.git.checkout(uri.commitid)
src = os.path.join(tmp_dir, uri.path)

resolved_file = self._resolve_file(src, self.cached_bundles_dir)
resolved_file = _resolve_file(src, self.cached_bundles_dir)
return self._translate(resolved_file)

def _resolve_models(self):
""" Resolve module files."""
for url in self.repos:
repo, tmp_dir = self._clone_repo(url, suffix='.yang')
repo, tmp_dir = _clone_repo(url, suffix='.yang')
for commitid in self.repos[url]:
repo.git.checkout(commitid)
for path in self.repos[url][commitid]:
src = os.path.join(tmp_dir, path)
bundles = self.repos[url][commitid][path]
for bundle in bundles:
self._resolve_file(src, bundle.resolved_models_dir)
_resolve_file(src, bundle.resolved_models_dir)

rmtree(tmp_dir)


def _add_symlink(bundle, dependency):
source = dependency.resolved_models_dir
link_name = os.path.basename(source)
link_name = os.path.join(bundle.resolved_models_dir, link_name)
os.symlink(source, link_name)


def _clone_repo(url, suffix=''):
tmp_dir = tempfile.mkdtemp(suffix)
repo = Repo.clone_from(url, tmp_dir)
return RepoDir(repo, tmp_dir)


def _resolve_file(src, dst_dir, rename=''):
""" Resolve file from src to dst directory.
"""
fname = os.path.basename(src)
logger.debug('Resolving file {} --> {}'.format(fname, dst_dir))
if rename == '':
dst = os.path.join(dst_dir, fname)
else:
dst = os.path.join(dst_dir, rename)
copy(src, dst)
return dst
13 changes: 7 additions & 6 deletions ydkgen/resolver/bundle_translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,14 +144,14 @@ def get_file_attrs(files, root, remote=None):

def get_dir_attrs(dirs, root, remote=None):
for d in dirs:
for (d, _, files) in walk(os.path.join(root, d.lstrip('/'))):
for (_, _, files) in walk(os.path.join(root, d.lstrip('/'))):
for res in get_file_attrs((os.path.join(d, f) for f in files),
root,
remote):
yield res


def get_git_attrs(repos, root, remote=None):
def get_git_attrs(repos):
for g in repos:
url, tmp_dir = g['url'], tempfile.mkdtemp(suffix='.yang')
logger.debug(('Bundle Translator: Cloning from %s --> %s'
Expand Down Expand Up @@ -204,17 +204,18 @@ def translate(in_file, out_file, root_dir):
for source in accepted_resources:
if source in data['models']:
get_fun = 'get_%s_attrs' % source
modules.extend(globals()[get_fun](data['models'][source],ydk_root))
modules.extend(globals()[get_fun](data['models'][source], ydk_root))

try:
name = data['name']
version = data['version']
core_version = data['core_version']
description = data['description']
except KeyError:
raise YdkGenException('Bundle file requires version and description.')
raise YdkGenException('Bundle profile requires to specify name, version, core_version and description.')

core_version = data['core_version'] if 'core_version' in data else version
long_description = data['long_description'] if 'long_description' in data else str()
definition = Bundle(load_profile_attr(in_file, 'name'), version, core_version, description, long_description)
definition = Bundle(name, version, core_version, description, long_description)
dependency = load_profile_attr(in_file, 'dependency')

output = Environment().from_string(TEMPLATE).render(
Expand Down

0 comments on commit 0fdd9fe

Please sign in to comment.