@@ -29,69 +29,42 @@ namespace ORTS.Common
2929 public static class VersionInfo
3030 {
3131 static readonly string ApplicationPath = Path . GetDirectoryName ( Process . GetCurrentProcess ( ) . MainModule . FileName ) ;
32- // GetRevision() must come before GetVersion()
33- /// <summary>Revision number , e.g. Release : "1648 ", experimental : "1649 ", local: ""</summary>
34- public static readonly string Revision = GetRevision ( "Revision.txt ") ;
35- /// <summary>Full version number, e.g. Release: "0.9.0.1648", experimental: "X.1649", local: ""</summary>
36- public static readonly string Version = GetVersion ( "Version.txt" ) ;
37- /// <summary>Full build number, e.g. "0.0.5223.24629 (2014-04-20 13:40:58Z)"</summary>
38- public static readonly string Build = GetBuild ( "ORTS.Common.dll" , "OpenRails.exe" , "Menu.exe" , "RunActivity.exe" ) ;
32+
33+ /// <summary>Full version , e.g. stable : "1.4 ", testing : "T1.4-1-g1234567 ", unstable: "U2021.01.01-0000", local: ""</summary>
34+ public static readonly string Version = GetVersion ( "OpenRails.exe ") ;
35+
36+ /// <summary>Full build, e.g. "0.0.5223.24629 (2014-04-20 13:40:58Z)"</summary>
37+ public static readonly string Build = GetBuild ( "OpenRails.exe" ) ;
38+
3939 /// <summary>Version, but if "", returns Build</summary>
4040 public static readonly string VersionOrBuild = GetVersionOrBuild ( ) ;
4141
42- static string GetRevision ( string fileName )
43- {
44- try
45- {
46- using ( var f = new StreamReader ( Path . Combine ( ApplicationPath , fileName ) ) )
47- {
48- var revision = f . ReadLine ( ) . Trim ( ) ;
49- if ( revision . StartsWith ( "$Revision:" ) && revision . EndsWith ( "$" ) && ! revision . Contains ( " 000 " ) )
50- return revision . Substring ( 10 , revision . Length - 11 ) . Trim ( ) ;
51- }
52- }
53- catch
54- {
55- }
56- return "" ;
57- }
58-
5942 static string GetVersion ( string fileName )
6043 {
6144 try
6245 {
63- using ( var f = new StreamReader ( Path . Combine ( ApplicationPath , fileName ) ) )
64- {
65- var version = f . ReadLine ( ) . Trim ( ) ;
66- if ( ! String . IsNullOrEmpty ( Revision ) )
67- return version + Revision ;
68- }
46+ var version = FileVersionInfo . GetVersionInfo ( Path . Combine ( ApplicationPath , fileName ) ) ;
47+ if ( version . ProductVersion != version . FileVersion )
48+ return version . ProductVersion ;
6949 }
7050 catch
7151 {
7252 }
7353 return "" ;
7454 }
7555
76- static string GetBuild ( params string [ ] fileNames )
56+ static string GetBuild ( string fileName )
7757 {
7858 var builds = new Dictionary < TimeSpan , string > ( ) ;
79- foreach ( var fileName in fileNames )
59+ try
8060 {
81- try
82- {
83- var version = FileVersionInfo . GetVersionInfo ( Path . Combine ( ApplicationPath , fileName ) ) ;
84- builds . Add ( new TimeSpan ( version . ProductBuildPart , 0 , 0 , version . ProductPrivatePart * 2 ) , version . ProductVersion ) ;
85- }
86- catch
87- {
88- }
61+ var version = FileVersionInfo . GetVersionInfo ( Path . Combine ( ApplicationPath , fileName ) ) ;
62+ var datetime = new DateTime ( 2000 , 1 , 1 , 0 , 0 , 0 , DateTimeKind . Utc ) ;
63+ var timespan = new TimeSpan ( version . FileBuildPart , 0 , 0 , version . FilePrivatePart * 2 ) ;
64+ return String . Format ( "{0} ({1:u})" , version . FileVersion , datetime + timespan ) ;
8965 }
90- if ( builds . Count > 0 )
66+ catch
9167 {
92- var datetime = new DateTime ( 2000 , 1 , 1 , 0 , 0 , 0 , DateTimeKind . Utc ) ;
93- var timespan = builds . Keys . OrderBy ( ts => ts ) . Last ( ) ;
94- return String . Format ( "{0} ({1:u})" , builds [ timespan ] , datetime + timespan ) ;
9568 }
9669 return "" ;
9770 }
@@ -102,70 +75,62 @@ static string GetVersionOrBuild()
10275 }
10376
10477 /// <summary>
105- /// Find whether a requested version and build are valid for this build
78+ /// Compares a version and build with the youngest version which failed to restore, to see if that version/ build is likely to restore successfully
10679 /// </summary>
107- /// <param name="version">version to test again </param>
108- /// <param name="build">build to test again </param>
109- /// <param name="youngestFailedToResume ">youngest build that failed to resume </param>
80+ /// <param name="version">version to test</param>
81+ /// <param name="build">build to test</param>
82+ /// <param name="youngestVersionFailedToRestore ">youngest version that failed to restore </param>
11083 /// <returns>true or false when able to determine validity, null otherwise</returns>
111- public static bool ? GetValidity ( string version , string build , int youngestFailedToResume )
84+ public static bool ? GetValidity ( string version , string build , string youngestVersionFailedToRestore )
11285 {
113- int revision = GetRevisionFromVersion ( version ) ;
114- int programRevision = 0 ;
115- try // as Convert.ToInt32() can fail and version may be ""
116- {
117- programRevision = Convert . ToInt32 ( VersionInfo . Revision ) ;
118- }
119- catch { } // ignore errors
120- //MessageBox.Show(String.Format("VersionInfo.Build = {0}, build = {1}, version = {2}, youngestFailedToResume = {3}", VersionInfo.Build, build, Version, youngestFailedToResume));
121- if ( revision != 0 ) // compiled remotely by Open Rails
122- {
123- if ( revision == programRevision )
124- {
125- return true ;
126- }
127- else
128- {
129- if ( revision > youngestFailedToResume // 1. Normal situation
130- || programRevision < youngestFailedToResume ) // 2. If an old version of OR is used, then attempt to load Saves
131- // which would be blocked by the current version of OR
132- {
133- return null ;
134- }
135- }
136- }
137- else // compiled locally
138- {
139- if ( build . EndsWith ( VersionInfo . Build ) )
140- {
141- return true ;
142- }
143- else
144- {
145- return null ;
146- }
147- }
148- return false ; // default validity
86+ // Validity rules:
87+ // - Same version and build --> yes
88+ // - Same non-empty version --> yes
89+ // - Unable to parse save or program version --> maybe
90+ // - Save version > setting --> maybe
91+ // - Program version < setting --> maybe
92+ // - Default --> no
93+
94+ if ( Version == version && Build == build ) return true ;
95+ if ( Version . Length > 0 && version . Length > 0 && Version == version ) return true ;
96+ var saveVersion = ParseVersion ( version ) ;
97+ var programVersion = ParseVersion ( Version ) ;
98+ var settingVersion = ParseVersion ( youngestVersionFailedToRestore ) ;
99+ if ( saveVersion . Major == 0 || programVersion . Major == 0 ) return null ;
100+ if ( saveVersion > settingVersion ) return null ;
101+ if ( programVersion < settingVersion ) return null ;
102+ return false ;
149103 }
150104
151105 /// <summary>
152- /// Find the revision number (e.g. 1648) from the full version (e.g. 0.9.0.1648 or X.1648 or X1648)
106+ /// Converts many possible Open Rails versions into a standard Version struct
153107 /// </summary>
154- /// <param name="version">full version</param>
155- public static int GetRevisionFromVersion ( string fullVersion )
108+ /// <param name="version">text version to parse </param>
109+ public static Version ParseVersion ( string version )
156110 {
157- var versionParts = fullVersion . Split ( '.' ) ;
158- var revision = 0 ;
159- try
160- {
161- var version = versionParts [ versionParts . Length - 1 ] ;
162- if ( version . StartsWith ( "X" ) )
163- version = version . Substring ( 1 ) ;
164- // Might throw an error if it isn't a number like we expect.
165- revision = Convert . ToInt32 ( version ) ;
166- }
167- catch { }
168- return revision ;
111+ // Version numbers which we do parse:
112+ // - 0.9.0.1648 --> 0.9
113+ // - 1.3.1.4328 --> 1.3.1
114+ // - T1.3.1-241-g6ff150c21 --> 1.3.1.241
115+ // - X1.3.1-370-g7df5318c2 --> 1.3.1.370
116+ // - 1.4 --> 1.4
117+ // - 1.4-rc1 --> 1.4
118+ // - T1.4-2-g7db094316 --> 1.4.0.2
119+ // Version numbers which we do NOT parse:
120+ // - U2019.07.25-2200
121+ // - U2021.06.25-0406
122+ // - X.1648
123+ // - X1648
124+
125+ if ( version . StartsWith ( "T" ) || version . StartsWith ( "X" ) ) version = version . Substring ( 1 ) ;
126+
127+ var versionParts = version . Split ( '-' ) ;
128+ if ( ! System . Version . TryParse ( versionParts [ 0 ] , out var parsedVersion ) ) return new Version ( ) ;
129+
130+ var commits = 0 ;
131+ if ( versionParts . Length > 1 ) int . TryParse ( versionParts [ 1 ] , out commits ) ;
132+ // parsedVersion.Build will be -1 if the version only has major and minor, but we need the build number >= 0 here
133+ return new Version ( parsedVersion . Major , parsedVersion . Minor , Math . Max ( 0 , parsedVersion . Build ) , commits ) ;
169134 }
170135 }
171136}
0 commit comments