2 * --- T2-COPYRIGHT-NOTE-BEGIN ---
3 * This copyright note is auto-generated by scripts/Create-CopyPatch.
5 * T2 SDE: source/UpdateList.cc
6 * Copyright (C) 2004 - 2021 The T2 SDE Project
8 * More information can be found in the files COPYING and README.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2 of the License. A copy of the
13 * GNU General Public License can be found in the file COPYING.
14 * --- T2-COPYRIGHT-NOTE-END ---
20 #include "desc-parser.hh"
24 #include <sys/types.h>
31 using namespace Utility
;
33 const bool debug
= false;
35 std::vector
<std::string
> suffixes
;
39 std::string::size_type
next_part (const std::string
& s
,
40 std::string::size_type i
)
44 const std::ctype
<char>& ct
= std::use_facet
<std::ctype
<char> >(loc
);
46 // catch range exceptions
48 // type to search for transition
49 int type_mask
= std::ctype
<char>::alpha
;
51 type_mask
= std::ctype
<char>::digit
;
53 for (; i
< s
.size() && ct
.is(type_mask
, s
[i
]); ++i
) {
57 if (!(ct
.is((std::ctype
<char>::alpha
| std::ctype
<char>::digit
),
64 std::cout
<< "extracted part: " << val
<< std::endl
;
68 std::string::size_type
size() const {
72 char operator[] (std::string::size_type i
) const {
80 const std::string
& str () const {
84 bool same_cclass (char a
, char b
) const {
85 // I'm sure this could be done more elegant
86 return ( (isalpha(a
) && isalpha(b
)) ||
87 (isdigit(a
) && isdigit(b
)) );
90 bool operator< (const subversion
& other
) const {
91 // special case for char < number
92 try { // catch range exceptions ;-)
93 if (!same_cclass(val
[0], other
.val
[0]))
94 return (isalpha(val
[0]));
96 // special case for numbers only, so real values are compared
97 if (isdigit(val
[0]) && isdigit(other
.val
[0])) {
98 int int_val
, other_int_val
;
99 int_val
= atoi(val
.c_str());
100 other_int_val
= atoi(other
.val
.c_str());
102 std::cout
<< "Intergers only: " << int_val
<< " "
103 << other_int_val
<< std::endl
;
105 // do not compare overly large versions - they are most probably
106 // a data (e.g. 3-... vs 2004-...)
107 if (std::abs(int_val
- other_int_val
) > 100) {
109 std::cout
<< "Version differ too much - skipped ..."
111 return true; // always lower ,-)
114 return int_val
< other_int_val
;
118 return val
< other
.val
;
121 bool operator> (const subversion
& other
) const {
122 // special case for char < number
123 try { // catch range exceptions ;-)
124 if (!same_cclass(val
[0], other
.val
[0]))
125 return (isalpha(other
.val
[0]));
127 // special case for numbers only, so real values are compared
128 if (isdigit(val
[0]) && isdigit(other
.val
[0])) {
129 int int_val
, other_int_val
;
130 int_val
= atoi(val
.c_str());
131 other_int_val
= atoi(other
.val
.c_str());
133 std::cout
<< "Intergers only: " << int_val
<< " "
134 << other_int_val
<< std::endl
;
136 // do not compare overly large versions - they are most probably
137 // a data (e.g. 3-... vs 2004-...)
138 if (std::abs(int_val
- other_int_val
) > 100) {
140 std::cout
<< "Version differ too much - skipped ..."
145 return int_val
> other_int_val
;
150 return val
> other
.val
;
157 // maybe inherit std::string? -ReneR
166 Version (const std::string
& i_version
) {
170 void ExtractFromFilename (const std::string
& filename
) {
172 // start scan at index once, since there must be a package name
173 for (std::string::size_type i
= 1; i
< filename
.size(); ++i
) {
174 // match the first digit or -digit if present
175 if (isdigit(filename
[i
])) {
177 version
= filename
.substr(i
);
178 else if (filename
[i
-1] == '-' || filename
[i
-1] == '_') {
179 version
= filename
.substr(i
);
186 std::cout
<< "No version extracted!" << std::endl
;
188 std::cout
<< "Vesion set to: " << version
<< std::endl
;
192 std::string::size_type
size() const {
193 return version
.size();
196 char operator[] (std::string::size_type i
) const {
200 int compare (const Version
& a
, const Version
& b
) const
203 std::cout
<< "Comparing: " << a
.str() << " with " << b
.str()
206 std::string::size_type i
, j
;
207 subversion subv_a
, subv_b
;
208 for (i
= j
= 0; i
< a
.size() && j
< b
.size();) {
210 i
= subv_a
.next_part(a
.str(), i
);
211 j
= subv_b
.next_part(b
.str(), j
);
214 std::cout
<< subv_a
.str() << " vs " << subv_b
.str() << ": ";
216 if (subv_a
< subv_b
) {
218 std::cout
<< "... <" << std::endl
;
221 if (subv_a
> subv_b
) {
223 std::cout
<< "... >" << std::endl
;
228 std::cout
<< "=, " << std::endl
;
231 i
= subv_a
.next_part(a
.str(), i
);
232 j
= subv_b
.next_part(b
.str(), j
);
235 std::cout
<< "Final: " << subv_a
.str() << " vs " << subv_b
.str() << ": ";
239 if (isdigit(subv_a
[0])) {
241 std::cout
<< "... >" << std::endl
;
246 std::cout
<< "... <" << std::endl
;
253 if (isdigit(subv_a
[0])) {
255 std::cout
<< "... <" << std::endl
;
260 std::cout
<< "... >" << std::endl
;
266 std::cout
<< "... =" << std::endl
;
270 bool operator< (const Version
& b
) const
272 return compare(*this, b
) == -1;
275 bool operator> (const Version
& b
) const
277 return compare(*this, b
) == 1;
280 bool operator== (const Version
& b
) const
282 return version
== b
.version
;
285 const std::string
& str () const {
295 void ParseList (std::string file
, std::istream
& s
,
296 const bool odd
= true, const bool noprefix
= false, const bool beta
= true, const bool nineties
= false) {
297 // search for a matching extension
298 std::string templ
= file
;
299 std::string suffix
= "";
301 for (unsigned int i
= 0; i
< suffixes
.size(); ++i
) {
302 std::string
& test
= suffixes
[i
];
303 std::string::size_type s_pos
= templ
.rfind(test
);
304 if (s_pos
!= std::string::npos
) {
306 templ
= templ
.substr(0, s_pos
);
312 std::vector
<Version
> versions
;
313 std::vector
<Version
> newer_versions
;
315 version
.ExtractFromFilename (templ
);
319 std::string::size_type idx
= templ
.rfind(version
.str());
320 if (idx
== std::string::npos
)
323 prefix
= templ
.substr(0, idx
);
325 if (noprefix
) prefix
= "";
327 std::cout
<< file
<< "(" << version
.str() << ") ---> " << prefix
<< "???" << suffix
<< std::endl
;
330 // read a line and search for the prefix
333 idx
= token
.find(prefix
);
335 if (idx
!= std::string::npos
) {
336 std::string::size_type idx2
;
337 if (suffix
.length() > 0)
338 idx2
= token
.find(suffix
, idx
+1);
340 idx2
= token
.find(' ', idx
+1);
341 if (idx2
== std::string::npos
)
342 idx2
= token
.length() - 1;
345 if (idx2
!= std::string::npos
) {
346 std::string::size_type begin
= idx
;
347 std::string::size_type length
= (idx2
-idx
);
349 std::string matched
= token
.substr(begin
, length
);
351 v
.ExtractFromFilename (matched
);
353 if (std::find (versions
.begin(), versions
.end(), v
) == versions
.end()) {
354 std::string s
= v
.str();
355 std::transform(s
.begin(), s
.end(), s
.begin(), ::tolower
);
357 if (s
.find("alpha") != std::string::npos
||
358 s
.find("beta") != std::string::npos
||
359 // TODO: pre[0-9], rc[0-9], r987
360 // TODO: very high last version, like 1.2.99
361 s
.find("pre") != std::string::npos
||
362 s
.find("rc") != std::string::npos
)
368 std::string::size_type i
;
369 i
= subv
.next_part(v
.str(), 0);
372 i
= subv
.next_part(v
.str(), i
);
373 int minorv
= atoi(subv
.str().c_str());
375 // only if it has patch level (e.g. 1.2.3, not 1.3)
376 i
= subv
.next_part(v
.str(), i
);
377 int patchv
= subv
.empty() ? -1 : atoi(subv
.str().c_str());
379 std::cout
<< "subv> " << v
.str() << " " << subv
.str() << " minor: " << minorv
<< " patch: " << patchv
<< " = " << i
<< std::endl
;
381 if (!odd
&& !subv
.empty() && (minorv
& 1))
384 // TODO: based on prev version context
385 if (!nineties
&& patchv
>= 90)
390 versions
.push_back(v
);
397 for (unsigned int i
= 0; i
< versions
.size(); ++i
) {
398 int sign
= version
.compare(versions
[i
], version
);
400 std::cout
<< "[MATCH] (" << versions
[i
].str() << ")";
406 std::cout
<< " [=]" << std::endl
;
409 std::cout
<< " [+]" << std::endl
;
410 newer_versions
.push_back(versions
[i
]);
413 std::cout
<< " [-]" << std::endl
;
419 std::cout
<< "-----------------------" << std::endl
;
421 std::sort(newer_versions
.begin(), newer_versions
.end());
422 if (newer_versions
.size() > 0)
423 std::cout
<< "XXX " << prefix
<< newer_versions
.back().str() << std::endl
;
425 std::cout
<< "-----------------------" << std::endl
;
428 void GenList (const DownloadInfo
& info
, const bool odd
, const bool noprefix
, const bool beta
)
431 dl
.SetConnectTimeout(15);
435 dl
.Download(info
.url
); //, 0, 200000); // 416 Range Not Satisfiable (RFC 7233)
436 std::auto_ptr
<std::ifstream
> s
= dl
.OpenFile();
437 ParseList(info
.file
, *s
, odd
, noprefix
, beta
);
441 catch (TimeoutException e
) {
442 std::cout
<< "Operation timeout" << std::endl
;
444 catch (UnsupportedProtocolException e
) {
445 std::cout
<< "Unsupported protocol : " << info
.protocol
<< std::endl
;
447 catch (MalformedUrlException e
) {
448 std::cout
<< "Malformed URL or invalid URL options "
449 << info
.url
<< std::endl
;
451 catch (ConnectErrorException e
) {
452 std::cout
<< "Could not connect to host" << std::endl
;
454 catch (AccessDeniedException e
) {
455 std::cout
<< "Access denied or invalid user/pass" << std::endl
;
457 catch (DoesNotExistException e
) {
458 std::cout
<< "File does not exist" << std::endl
;
460 catch (CurlException e
) {
461 std::cout
<< "operation canceled due to errors executing '"
462 << dl
.GetCommand() << "'" << std::endl
;
468 void Check4Updates (const Package
& package
, const bool odd
, const bool noprefix
, const bool beta
,
469 const std::string url
= "")
471 unsigned int no_downloads
= package
.download
.download_infos
.size();
472 for (unsigned int dln
= 0; dln
< no_downloads
; ++dln
) {
473 DownloadInfo info
= package
.download
.download_infos
[dln
];
474 if (info
.protocol
!= "http" && info
.protocol
!= "https" &&
475 info
.protocol
!= "ftp")
478 // Apply translations ...
479 char* cmd
[] = {"sed", "-f", "misc/share/CVTranslations", 0};
480 pstream
sed ("sed", cmd
);
484 else if (!package
.cv_url
.value
.empty())
485 info
.url
= package
.cv_url
.value
;
487 sed
<< info
.url
<< std::endl
;
490 std::string translated_url
;
491 sed
>> translated_url
;
493 if (translated_url
!= info
.url
) {
494 std::cout
<< "Download URL translated!" << std::endl
;
495 info
.url
= translated_url
;
498 std::cout
<< "Checking updates for " << info
.url
<< std::endl
;
500 GenList(info
, odd
, noprefix
, beta
);
504 int main (int argc
, char* argv
[])
508 suffixes
.push_back(".tar.zst");
509 suffixes
.push_back(".tar.bz2");
510 suffixes
.push_back(".tar.xz");
511 suffixes
.push_back(".tar.gz");
512 suffixes
.push_back(".tar.lz");
513 suffixes
.push_back(".tzst");
514 suffixes
.push_back(".tbz2");
515 suffixes
.push_back(".tbz");
516 suffixes
.push_back(".tgz");
517 suffixes
.push_back(".bz2");
518 suffixes
.push_back(".tlz");
519 suffixes
.push_back(".gz");
520 suffixes
.push_back(".zip");
521 suffixes
.push_back(".xz");
522 suffixes
.push_back(".zst");
523 suffixes
.push_back(".lz");
526 std::vector
<Version
> versions
;
527 versions
.push_back(Version("1.2.2"));
528 versions
.push_back(Version("1.2.12"));
529 versions
.push_back(Version("1.2.4"));
530 versions
.push_back(Version("1.2.3"));
531 versions
.push_back(Version("1.2.3b"));
532 versions
.push_back(Version("1.2.3a"));
533 versions
.push_back(Version("1.2.3-pre9"));
534 versions
.push_back(Version("1.2.3-pre12"));
535 versions
.push_back(Version("1.2.3-beta"));
536 versions
.push_back(Version("1.2.3-rc2"));
537 versions
.push_back(Version("1.2.3-alpha"));
538 versions
.push_back(Version("1.2.3-rc1"));
539 versions
.push_back(Version("1.2.3.1"));
540 versions
.push_back(Version("2004-12-24"));
542 std::cout
<< "-----------------------" << std::endl
;
544 std::sort(versions
.begin(), versions
.end());
546 for (unsigned int i
= 0; i
< versions
.size(); ++i
)
547 std::cout
<< " " << versions
[i
].str() << std::endl
;
549 std::cout
<< "-----------------------" << std::endl
;
552 bool odd
= false, noprefix
= false, beta
= false;
554 ++argv
; --argc
; // progname
556 const std::string
opt(*argv
);
557 if (opt
== "--odd") {
561 } else if (opt
== "--no-prefix") {
565 } else if (opt
== "--url") {
577 for (int i
= 0; i
< argc
; ++i
)
581 // check if package name or path is given
582 std::string fname
= argv
[i
];
584 if (stat(fname
.c_str(), &statbuf
)) {
585 fname
= "package/*/" + fname
+ "/" + fname
+ ".desc";
586 // std::cout << "Checking " << fname << std::endl;
589 if (x
.begin() != x
.end()) {
591 // std::cout << "Found " << fname << std::endl;
596 package
.ParsePackage (fname
);
597 Check4Updates (package
, odd
, noprefix
, beta
, url
);