001 /* 002 * Jpkg - Java library and tools for operating system package creation. 003 * 004 * Copyright (c) 2007 Three Rings Design, Inc. 005 * All rights reserved. 006 * 007 * Redistribution and use in source and binary forms, with or without 008 * modification, are permitted provided that the following conditions 009 * are met: 010 * 1. Redistributions of source code must retain the above copyright 011 * notice, this list of conditions and the following disclaimer. 012 * 2. Redistributions in binary form must reproduce the above copyright 013 * notice, this list of conditions and the following disclaimer in the 014 * documentation and/or other materials provided with the distribution. 015 * 3. Neither the name of the copyright owner nor the names of contributors 016 * may be used to endorse or promote products derived from this software 017 * without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 021 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 023 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 024 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 025 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 026 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 027 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 028 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 029 * POSSIBILITY OF SUCH DAMAGE. 030 */ 031 package com.threerings.jpkg.debian; 032 033 import java.util.regex.Pattern; 034 035 /** 036 * Holds and parses the Debian package version. 037 * @see <a href="http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version">Debian Policy Manual</a> 038 */ 039 public class PackageVersion 040 implements ControlFileData 041 { 042 /** 043 * Construct a fully populated PackageVersion object with the "upstream_version" field set 044 * to the supplied value. 045 * The supplied string may only contain alphanumeric characters, ".", "+", and "~". 046 * The Debian version and epoch fields of the version field will not be set, meaning they 047 * will have the default values assigned to them by the dpkg tools. 048 * If the supplied string does not match these rules a ControlDataInvalidException will be 049 * thrown. 050 * @throws ControlDataInvalidException 051 */ 052 public PackageVersion (String upstream_version) 053 throws ControlDataInvalidException 054 { 055 this(upstream_version, DEFAULT_DEBIAN_VERSION, DEFAULT_EPOCH); 056 } 057 058 /** 059 * Construct a fully populated PackageVersion object with the "upstream_version", 060 * "debian_version", and "epoch" set. 061 * The upstream version may only contain alphanumeric characters, ".", "+", "-", ":", and "~". 062 * The Debian version may only contain alphanumeric characters, "+", ".", and "~". 063 * It is conventional to start the Debian version at 1. 064 * Epoch must be 0 or greater. 0 is a safe default and indicates no epoch. 065 * If the supplied string does not match these rules a ControlDataInvalidException will be 066 * thrown. 067 * @throws ControlDataInvalidException 068 */ 069 public PackageVersion (String upstream_version, String debian_version, int epoch) 070 throws ControlDataInvalidException 071 { 072 _upstreamVersion = validateUpstreamVersion(upstream_version); 073 _debianVersion = validateDebianVersion(debian_version); 074 _epoch = validateEpoch(epoch); 075 } 076 077 // from ControlFileData 078 public String getField () 079 { 080 return "Version"; 081 } 082 083 // from ControlFileData 084 public String getFieldValue () 085 { 086 final StringBuilder builder = new StringBuilder(); 087 if (_epoch != DEFAULT_EPOCH) { 088 builder.append(_epoch).append(':'); 089 } 090 builder.append(_upstreamVersion); 091 if (!_debianVersion.equals(DEFAULT_DEBIAN_VERSION)) { 092 builder.append('-').append(_debianVersion); 093 } 094 return builder.toString(); 095 } 096 097 /** 098 * Validate the supplied package upstream version. 099 */ 100 private String validateUpstreamVersion (String version) 101 throws ControlDataInvalidException 102 { 103 if (!UPSTREAM_PATTERN.matcher(version).matches()) { 104 throw new ControlDataInvalidException( 105 "Upstream version must match the pattern. version=[" + version + "] pattern=[" + UPSTREAM_PATTERN.pattern() + "]"); 106 } 107 108 return version; 109 } 110 111 /** 112 * Validate the supplied package Debian version. 113 */ 114 private String validateDebianVersion (String version) 115 throws ControlDataInvalidException 116 { 117 if (!DEBIAN_PATTERN.matcher(version).matches()) { 118 throw new ControlDataInvalidException( 119 "Debian version must match the pattern. version=[" + version + "] pattern=[" + DEBIAN_PATTERN.pattern() + "]"); 120 } 121 122 return version; 123 } 124 125 /** 126 * Validate the supplied package Epoch. 127 */ 128 private int validateEpoch (int epoch) 129 throws ControlDataInvalidException 130 { 131 if (!(epoch >= 0)) { 132 throw new ControlDataInvalidException( 133 "Epoch must be equal to or greater than 0. epoch=[" + epoch + "]"); 134 } 135 136 return epoch; 137 } 138 139 /** 140 * The regex against which the package upstream version must match. 141 * From: <a href="http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version">Debian Policy Manual</a> 142 * "The upstream_version may contain only alphanumerics and the characters . + - : ~ 143 * (full stop, plus, hyphen, colon, tilde) and should start with a digit." If the Debian version 144 * is set, the upstream version may not contain a "-" and if the epoch is set, it may not contain 145 * a ":". We will simply never allow it to contain either of these characters for clarity. 146 */ 147 private static final Pattern UPSTREAM_PATTERN = Pattern.compile("[\\p{Digit}][\\p{Alnum}.+~]*"); 148 149 /** 150 * The regex against which the package upstream version must match. 151 * From: <a href="http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version">Debian Policy Manual</a> 152 * "This part of the version number specifies the version of the Debian package based on the 153 * upstream version. It may contain only alphanumerics and the characters + . ~ 154 * (plus, full stop, tilde) and is compared in the same way as the upstream_version is." 155 */ 156 private static final Pattern DEBIAN_PATTERN = Pattern.compile("[\\p{Alnum}+.~]+"); 157 158 /** The Debian project recommended default value for the Debian version. */ 159 private static final String DEFAULT_DEBIAN_VERSION = "1"; 160 161 /** The default value for the epoch, indicating no epoch. */ 162 private static final int DEFAULT_EPOCH = 0; 163 164 /** The package upstream version. */ 165 private final String _upstreamVersion; 166 167 /** The package Debian version. */ 168 private final String _debianVersion; 169 170 /** The package epoch. */ 171 private final int _epoch; 172 }