@@ -29,76 +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 ( "$" ) )
50- {
51- if ( ! revision . Contains ( " 000 " ) )
52- return revision . Substring ( 10 , revision . Length - 11 ) . Trim ( ) ;
53- }
54- else
55- {
56- return revision ;
57- }
58- }
59- }
60- catch
61- {
62- }
63- return "" ;
64- }
65-
6642 static string GetVersion ( string fileName )
6743 {
6844 try
6945 {
70- using ( var f = new StreamReader ( Path . Combine ( ApplicationPath , fileName ) ) )
71- {
72- var version = f . ReadLine ( ) . Trim ( ) ;
73- if ( ! String . IsNullOrEmpty ( Revision ) )
74- return version + "-" + Revision ;
75- }
46+ var version = FileVersionInfo . GetVersionInfo ( Path . Combine ( ApplicationPath , fileName ) ) ;
47+ if ( version . ProductVersion != version . FileVersion )
48+ return version . ProductVersion ;
7649 }
7750 catch
7851 {
7952 }
8053 return "" ;
8154 }
8255
83- static string GetBuild ( params string [ ] fileNames )
56+ static string GetBuild ( string fileName )
8457 {
8558 var builds = new Dictionary < TimeSpan , string > ( ) ;
86- foreach ( var fileName in fileNames )
59+ try
8760 {
88- try
89- {
90- var version = FileVersionInfo . GetVersionInfo ( Path . Combine ( ApplicationPath , fileName ) ) ;
91- builds . Add ( new TimeSpan ( version . ProductBuildPart , 0 , 0 , version . ProductPrivatePart * 2 ) , version . ProductVersion ) ;
92- }
93- catch
94- {
95- }
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 ) ;
9665 }
97- if ( builds . Count > 0 )
66+ catch
9867 {
99- var datetime = new DateTime ( 2000 , 1 , 1 , 0 , 0 , 0 , DateTimeKind . Utc ) ;
100- var timespan = builds . Keys . OrderBy ( ts => ts ) . Last ( ) ;
101- return String . Format ( "{0} ({1:u})" , builds [ timespan ] , datetime + timespan ) ;
10268 }
10369 return "" ;
10470 }
@@ -109,70 +75,62 @@ static string GetVersionOrBuild()
10975 }
11076
11177 /// <summary>
112- /// 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
11379 /// </summary>
114- /// <param name="version">version to test again </param>
115- /// <param name="build">build to test again </param>
116- /// <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>
11783 /// <returns>true or false when able to determine validity, null otherwise</returns>
118- public static bool ? GetValidity ( string version , string build , int youngestFailedToResume )
84+ public static bool ? GetValidity ( string version , string build , string youngestVersionFailedToRestore )
11985 {
120- int revision = GetRevisionFromVersion ( version ) ;
121- int programRevision = 0 ;
122- try // as Convert.ToInt32() can fail and version may be ""
123- {
124- programRevision = Convert . ToInt32 ( VersionInfo . Revision ) ;
125- }
126- catch { } // ignore errors
127- //MessageBox.Show(String.Format("VersionInfo.Build = {0}, build = {1}, version = {2}, youngestFailedToResume = {3}", VersionInfo.Build, build, Version, youngestFailedToResume));
128- if ( revision != 0 ) // compiled remotely by Open Rails
129- {
130- if ( revision == programRevision )
131- {
132- return true ;
133- }
134- else
135- {
136- if ( revision > youngestFailedToResume // 1. Normal situation
137- || programRevision < youngestFailedToResume ) // 2. If an old version of OR is used, then attempt to load Saves
138- // which would be blocked by the current version of OR
139- {
140- return null ;
141- }
142- }
143- }
144- else // compiled locally
145- {
146- if ( build . EndsWith ( VersionInfo . Build ) )
147- {
148- return true ;
149- }
150- else
151- {
152- return null ;
153- }
154- }
155- 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 ;
156103 }
157104
158105 /// <summary>
159- /// 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
160107 /// </summary>
161- /// <param name="version">full version</param>
162- public static int GetRevisionFromVersion ( string fullVersion )
108+ /// <param name="version">text version to parse </param>
109+ public static Version ParseVersion ( string version )
163110 {
164- var versionParts = fullVersion . Split ( '.' ) ;
165- var revision = 0 ;
166- try
167- {
168- var version = versionParts [ versionParts . Length - 1 ] ;
169- if ( version . StartsWith ( "X" ) )
170- version = version . Substring ( 1 ) ;
171- // Might throw an error if it isn't a number like we expect.
172- revision = Convert . ToInt32 ( version ) ;
173- }
174- catch { }
175- 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 ) ;
176134 }
177135 }
178136}
0 commit comments