Skip to content

Commit 2aaab5f

Browse files
Support new version policy for deb and rpm deps
Add Tarantool dependency to rpm or deb package only if it is not set up by user explicitly with --deps or --deps-file. Use version struct to build minimal and maximal requirements for packages based on new version policy. Old version policy (2.8 and less) cases are considered separately. Version struct parsing is strict so "lazy" versions without number of commits since tag and commit hash (like "2.8.0") are no longer supported since real Tarantool packages always have them. Use struct-based approach in integration tests, migrate them to new version policy. Part of #619
1 parent e37c98b commit 2aaab5f

File tree

6 files changed

+176
-51
lines changed

6 files changed

+176
-51
lines changed

cli/commands/pack.go

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,22 +57,62 @@ func init() {
5757
packCmd.Flags().StringVar(&ctx.Pack.SystemdUnitParamsPath, "unit-params-file", "", UnitParamsFileUsage)
5858
}
5959

60+
// isExplicitTarantoolDeps returns true if Tarantool was set up by user as a dependency
61+
// with --deps or --deps-file, false otherwise.
62+
func isExplicitTarantoolDeps(deps common.PackDependencies) bool {
63+
for _, v := range deps {
64+
if v.Name == "tarantool" {
65+
return true
66+
}
67+
}
68+
69+
return false
70+
}
71+
72+
// Tarantool dependence is added to rpm and deb packages deps, if it
73+
// wasn't set up explicitly. Dependency conditions is chosen based on
74+
// tarantool version used in cartridge-cli environment. Since development
75+
// builds and entrypoint builds normally are not available in package repos,
76+
// they are not supported as rpm/deb dependency. Minimal required version
77+
// is environment tarantool version, maximum is next tarantool major version.
78+
// Both modern and <= 2.8 version policies are supported.
6079
func addTarantoolDepIfNeeded(ctx *context.Ctx) error {
61-
if ctx.Tarantool.TarantoolIsEnterprise || !(ctx.Pack.Type == pack.RpmType || ctx.Pack.Type == pack.DebType) {
80+
var version common.TarantoolVersion
81+
var minVersion, maxVersion string
82+
var err error
83+
84+
if isExplicitTarantoolDeps(ctx.Pack.Deps) {
6285
return nil
6386
}
6487

65-
var tarantoolVersion string
66-
if ctx.Pack.Type == pack.RpmType {
67-
tarantoolVersion = strings.SplitN(ctx.Tarantool.TarantoolVersion, "-", 2)[0]
68-
} else if ctx.Pack.Type == pack.DebType {
69-
tarantoolVersion = ctx.Tarantool.TarantoolVersion
88+
if ctx.Tarantool.TarantoolIsEnterprise {
89+
return nil
7090
}
7191

72-
if err := ctx.Pack.Deps.AddTarantool(tarantoolVersion); err != nil {
73-
return fmt.Errorf("Failed to get tarantool dependency: %s", err)
92+
if (ctx.Pack.Type != pack.RpmType) && (ctx.Pack.Type != pack.DebType) {
93+
return nil
94+
}
95+
96+
if version, err = common.ParseTarantoolVersion(ctx.Tarantool.TarantoolVersion); err != nil {
97+
return err
98+
}
99+
100+
if version.IsDevelopmentBuild {
101+
return fmt.Errorf("Development build found. If you want to use Tarantool development build" +
102+
"as a dependency, set it up explicitly with --deps or --deps-file")
103+
}
104+
105+
if version.TagSuffix == "entrypoint" {
106+
return fmt.Errorf("Entrypoint build found. If you want to use Tarantool entrypoint build" +
107+
"as a dependency, set it up explicitly with --deps or --deps-file")
108+
}
109+
110+
if minVersion, err = common.GetMinimalRequiredVersion(version); err != nil {
111+
return err
74112
}
113+
maxVersion = common.GetNextMajorVersion(version)
75114

115+
ctx.Pack.Deps.AddTarantool(minVersion, maxVersion)
76116
return nil
77117
}
78118

cli/common/tarantool.go

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -170,16 +170,32 @@ func GetMajorMinorVersion(version string) string {
170170
return majorMinorVersion
171171
}
172172

173-
// GetNextMajorVersion computes next major version for a given one.
174-
// For example, for 1.10.3 it's 2
175-
func GetNextMajorVersion(versionStr string) (string, error) {
176-
version, err := goVersion.NewSemver(versionStr)
177-
if err != nil {
178-
return "", fmt.Errorf("Failed to parse Tarantool version: %s", err)
173+
// GetMinimalRequiredVersion computes minimal required Tarantool version for a package (rpm, deb).
174+
func GetMinimalRequiredVersion(ver TarantoolVersion) (string, error) {
175+
// Old-style package version policy allowed X.Y.Z-N versions for N > 0 .
176+
if (ver.Major == 2 && ver.Minor <= 8) || (ver.Major < 2) {
177+
return fmt.Sprintf("%d.%d.%d.%d", ver.Major, ver.Minor, ver.Patch, ver.CommitsSinceTag), nil
178+
}
179+
180+
if ver.IsDevelopmentBuild {
181+
return "", fmt.Errorf("Can't compute minimal required version for a development build")
182+
}
183+
184+
if ver.TagSuffix == "entrypoint" {
185+
return "", fmt.Errorf("Can't compute minimal required version for an entrypoint build")
179186
}
180187

181-
major := version.Segments()[0]
182-
return strconv.Itoa(major + 1), nil
188+
if ver.TagSuffix != "" {
189+
return fmt.Sprintf("%d.%d.%d~%s", ver.Major, ver.Minor, ver.Patch, ver.TagSuffix), nil
190+
}
191+
192+
return fmt.Sprintf("%d.%d.%d", ver.Major, ver.Minor, ver.Patch), nil
193+
}
194+
195+
// GetNextMajorVersion computes next Major version for a given one.
196+
// For example, for 1.10.3 it's 2 .
197+
func GetNextMajorVersion(ver TarantoolVersion) string {
198+
return strconv.Itoa(int(ver.Major) + 1)
183199
}
184200

185201
func GetCartridgeVersionStr(conn *connector.Conn) (string, error) {

cli/common/tarantool_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,3 +283,47 @@ func TestParseTarantoolVersion(t *testing.T) {
283283
}
284284
}
285285
}
286+
287+
type returnValueGetMinimalRequiredVersion struct {
288+
res string
289+
err error
290+
}
291+
292+
func TestGetTarantoolMinVersion(t *testing.T) {
293+
assert := assert.New(t)
294+
295+
testCases := map[string]returnValueGetMinimalRequiredVersion{
296+
"3.0.0-rc1-0-g7da4b1438": {res: "3.0.0~rc1", err: nil},
297+
"2.10.0-beta1-0-g7da4b1438": {res: "2.10.0~beta1", err: nil},
298+
"2.10.0-0-g7da4b1438": {res: "2.10.0", err: nil},
299+
"2.9.0-alpha1-0-g7da4b1438": {res: "2.9.0~alpha1", err: nil},
300+
"2.8.2-0-gfc96d10f5": {res: "2.8.2.0", err: nil},
301+
"1.10.11-21-g543e2a1ec0": {res: "1.10.11.21", err: nil},
302+
303+
"2.10.1-entrypoint-0-gc2438eeb1": {
304+
res: "",
305+
err: fmt.Errorf("Can't compute minimal required version for an entrypoint build"),
306+
},
307+
"2.10.1-23-g0c2e2a1ec-dev": {
308+
res: "",
309+
err: fmt.Errorf("Can't compute minimal required version for a development build"),
310+
},
311+
"2.10.0-beta1-3-g4b17da438-dev": {
312+
res: "",
313+
err: fmt.Errorf("Can't compute minimal required version for a development build"),
314+
},
315+
}
316+
317+
for version, output := range testCases {
318+
ver, verErr := ParseTarantoolVersion(version)
319+
assert.Nil(verErr)
320+
321+
res, err := GetMinimalRequiredVersion(ver)
322+
if output.err == nil {
323+
assert.Nil(err)
324+
assert.Equal(output.res, res)
325+
} else {
326+
assert.Equal(output.err, err)
327+
}
328+
}
329+
}

cli/common/utils.go

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,28 +34,20 @@ type PackDependency struct {
3434

3535
type PackDependencies []PackDependency
3636

37-
func (deps *PackDependencies) AddTarantool(tarantoolVersion string) error {
38-
tarantoolMinVersion := tarantoolVersion
39-
tarantoolMaxVersion, err := GetNextMajorVersion(tarantoolMinVersion)
40-
if err != nil {
41-
return fmt.Errorf("Failed to get next major version of Tarantool %s", err)
42-
}
43-
37+
func (deps *PackDependencies) AddTarantool(minVersion, maxVersion string) {
4438
*deps = append(*deps, PackDependency{
4539
Name: "tarantool",
4640
Relations: []DepRelation{
4741
{
4842
Relation: ">=",
49-
Version: tarantoolMinVersion,
43+
Version: minVersion,
5044
},
5145
{
5246
Relation: "<",
53-
Version: tarantoolMaxVersion,
47+
Version: maxVersion,
5448
},
5549
},
5650
})
57-
58-
return nil
5951
}
6052

6153
var bufSize int64 = 10000

test/integration/pack/test_pack.py

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
check_param_in_unit_files, clear_project_rocks_cache,
2222
extract_app_files, extract_deb, extract_rpm, find_archive,
2323
get_rocks_cache_path, get_rockspec_path, recursive_listdir,
24-
run_command_and_get_output, tarantool_enterprise_is_used,
25-
tarantool_version, validate_version_file)
24+
run_command_and_get_output, tarantool_dict_version,
25+
tarantool_enterprise_is_used, validate_version_file)
2626

2727

2828
# ########
@@ -99,13 +99,19 @@ def deb_archive(cartridge_cmd, tmpdir, light_project, request):
9999

100100
@pytest.fixture(scope="session")
101101
def tarantool_versions():
102-
min_deb_version = re.findall(r'\d+\.\d+\.\d+-\d+-\S+', tarantool_version())[0]
103-
max_deb_version = str(int(re.findall(r'\d+', tarantool_version())[0]) + 1)
104-
min_rpm_version = re.findall(r'\d+\.\d+\.\d+', tarantool_version())[0]
105-
max_rpm_version = max_deb_version # Their format is the same
102+
ver = tarantool_dict_version()
103+
if (ver['Major'] == 2 and ver['Minor'] <= 8) or (ver['Major'] < 2):
104+
min_version = f"{ver['Major']}.{ver['Minor']}.{ver['Patch']}.{ver['CommitsSinceTag']}"
105+
else:
106+
if ver['TagSuffix'] is not None:
107+
min_version = f"{ver['Major']}.{ver['Minor']}.{ver['Patch']}~{ver['TagSuffix']}"
108+
else:
109+
min_version = f"{ver['Major']}.{ver['Minor']}.{ver['Patch']}"
110+
111+
max_version = f"{ver['Major'] + 1}"
106112

107-
return {"min": {"deb": min_deb_version, "rpm": min_rpm_version},
108-
"max": {"deb": max_deb_version, "rpm": max_rpm_version}}
113+
return {"min": {"deb": min_version, "rpm": min_version},
114+
"max": {"deb": max_version, "rpm": max_version}}
109115

110116

111117
# #####
@@ -134,7 +140,7 @@ def test_tgz(tgz_archive, tmpdir):
134140
assert_filemodes(project, extract_dir)
135141

136142

137-
def test_rpm(rpm_archive, tmpdir):
143+
def test_rpm(rpm_archive, tmpdir, tarantool_versions):
138144
project = rpm_archive.project
139145

140146
# archive files should be extracted to the empty directory
@@ -145,7 +151,7 @@ def test_rpm(rpm_archive, tmpdir):
145151
extract_rpm(rpm_archive.filepath, extract_dir)
146152

147153
if not tarantool_enterprise_is_used():
148-
assert_tarantool_dependency_rpm(rpm_archive.filepath)
154+
assert_tarantool_dependency_rpm(rpm_archive.filepath, tarantool_versions)
149155

150156
check_package_files(project, extract_dir)
151157
assert_files_mode_and_owner_rpm(project, rpm_archive.filepath)
@@ -158,7 +164,7 @@ def test_rpm(rpm_archive, tmpdir):
158164
assert process.returncode == 0, "RPM signature isn't correct"
159165

160166

161-
def test_deb(deb_archive, tmpdir):
167+
def test_deb(deb_archive, tmpdir, tarantool_versions):
162168
project = deb_archive.project
163169

164170
# archive files should be extracted to the empty directory
@@ -191,7 +197,7 @@ def test_deb(deb_archive, tmpdir):
191197
assert os.path.exists(os.path.join(control_dir, filename))
192198

193199
if not tarantool_enterprise_is_used():
194-
assert_tarantool_dependency_deb(os.path.join(control_dir, 'control'))
200+
assert_tarantool_dependency_deb(os.path.join(control_dir, 'control'), tarantool_versions)
195201

196202
# check if postinst script set owners correctly
197203
with open(os.path.join(control_dir, 'postinst')) as postinst_script_file:

test/utils.py

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -532,19 +532,16 @@ def assert_dependencies_deb(filename, deps, tarantool_versions, tmpdir):
532532
assert all(dep in output for dep in deps)
533533

534534

535-
def assert_tarantool_dependency_deb(filename):
535+
def assert_tarantool_dependency_deb(filename, tarantool_versions):
536536
with open(filename) as control:
537537
control_info = control.read()
538538

539539
depends_str = re.search('Depends: (.*)', control_info)
540540
assert depends_str is not None
541541

542-
min_version = re.findall(r'\d+\.\d+\.\d+-\d+-\S+', tarantool_version())[0]
543-
max_version = str(int(re.findall(r'\d+', tarantool_version())[0]) + 1)
544-
545542
deps = depends_str.group(1)
546-
assert 'tarantool (>= {})'.format(min_version) in deps
547-
assert 'tarantool (<< {})'.format(max_version) in deps
543+
assert 'tarantool (>= {})'.format(tarantool_versions["min"]["deb"]) in deps
544+
assert 'tarantool (<< {})'.format(tarantool_versions["max"]["deb"]) in deps
548545

549546

550547
def assert_dependencies_rpm(filename, deps, tarantool_versions):
@@ -569,7 +566,7 @@ def assert_dependencies_rpm(filename, deps, tarantool_versions):
569566
assert rpm.headers['requireversion'][i].decode('ascii') == dep[2]
570567

571568

572-
def assert_tarantool_dependency_rpm(filename):
569+
def assert_tarantool_dependency_rpm(filename, tarantool_versions):
573570
with rpmfile.open(filename) as rpm:
574571
dependency_keys = ['requirename', 'requireversion', 'requireflags']
575572
for key in dependency_keys:
@@ -579,15 +576,12 @@ def assert_tarantool_dependency_rpm(filename):
579576
assert len(rpm.headers['requireversion']) == 2
580577
assert len(rpm.headers['requireflags']) == 2
581578

582-
min_version = re.findall(r'\d+\.\d+\.\d+', tarantool_version())[0]
583-
max_version = str(int(re.findall(r'\d+', tarantool_version())[0]) + 1)
584-
585579
assert rpm.headers['requirename'][0].decode('ascii') == 'tarantool'
586-
assert rpm.headers['requireversion'][0].decode('ascii') == min_version
580+
assert rpm.headers['requireversion'][0].decode('ascii') == tarantool_versions["min"]["rpm"]
587581
assert rpm.headers['requireflags'][0] == 0x08 | 0x04 # >=
588582

589583
assert rpm.headers['requirename'][1].decode('ascii') == 'tarantool'
590-
assert rpm.headers['requireversion'][1].decode('ascii') == max_version
584+
assert rpm.headers['requireversion'][1].decode('ascii') == tarantool_versions["max"]["rpm"]
591585
assert rpm.headers['requireflags'][1] == 0x02 # <
592586

593587

@@ -1394,3 +1388,36 @@ def get_response_data(response):
13941388
assert 'errors' not in response_json, response_json
13951389

13961390
return response_json['data']
1391+
1392+
1393+
def parse_tarantool_version(s):
1394+
regstr = (r'^Tarantool\s(?:Enterprise\s)?' +
1395+
r'(?P<Major>\d+)\.(?P<Minor>\d+)?\.(?P<Patch>\d+)' +
1396+
r'(?:-(?P<TagSuffix>alpha\d+|beta\d+|rc\d+|entrypoint))?' +
1397+
r'-(?P<CommitsSinceTag>\d+)-(?P<CommitHashId>g[0-9a-f]+)' +
1398+
r'(?:-(?P<EnterpriseSDKRevision>r\d+)(?:-(?P<EnterpriseIsOnMacOS>macos))?)?' +
1399+
r'(?:-(?P<IsDevelopmentBuild>dev))?$')
1400+
1401+
r = re.match(regstr, s)
1402+
assert r is not None
1403+
ver = r.groupdict()
1404+
assert len(ver) != 0
1405+
1406+
ver['Major'] = int(ver['Major'])
1407+
ver['Minor'] = int(ver['Minor'])
1408+
ver['Patch'] = int(ver['Patch'])
1409+
ver['CommitsSinceTag'] = int(ver['CommitsSinceTag'])
1410+
ver['EnterpriseIsOnMacOS'] = (ver['EnterpriseIsOnMacOS'] is not None)
1411+
ver['IsDevelopmentBuild'] = (ver['IsDevelopmentBuild'] is not None)
1412+
1413+
return ver
1414+
1415+
1416+
def tarantool_dict_version():
1417+
s = tarantool_version()
1418+
ver = parse_tarantool_version(s)
1419+
1420+
assert ver['TagSuffix'] != 'entrypoint'
1421+
assert ver['IsDevelopmentBuild'] is False
1422+
1423+
return ver

0 commit comments

Comments
 (0)