HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_PackageUtils.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_PackageUtils.h
7  *
8  * COMMENTS: Package utility classes and helpers.
9  */
10 
11 #ifndef UT_PackageUtils_H
12 #define UT_PackageUtils_H
13 
14 #include "UT_API.h"
15 #include "UT_Array.h"
16 #include "UT_Assert.h"
17 #include "UT_DirUtil.h"
18 #include "UT_SharedPtr.h"
19 #include "UT_StringArray.h"
20 #include "UT_StringMap.h"
21 #include "UT_StringSet.h"
22 #include "UT_StringStream.h"
23 #include "UT_VarScan.h"
24 #include <SYS/SYS_ParseNumber.h>
25 #include <SYS/SYS_Platform.h>
26 #include <SYS/SYS_VersionUtil.h>
27 
28 #include <hboost/any.hpp>
29 #include <patchlevel.h> // PY_MAJOR_VERSION
30 #include <tools/henv.h>
31 #include <tools/hpath.h>
32 
33 #include <cctype>
34 #include <iostream>
35 
36 #ifdef NO_VALUE
37 #undef NO_VALUE
38 #endif
39 
40 namespace UT_Package
41 {
42 namespace utils
43 {
44 constexpr UT_StringLit klog_error = "ERROR";
45 constexpr UT_StringLit klog_info = "INFO";
46 constexpr UT_StringLit klog_warning = "WARNING";
48 
49 static const char *path_sep()
50 {
51  return PATH_SEP_STRING;
52 }
53 
54 static char path_sep_char()
55 {
56  return PATH_SEP_CHAR;
57 }
58 
59 static const char *vardef_sep()
60 {
61  return "-";
62 }
63 
64 static UT_StringHolder makeVarRef(const char * var_name, bool use_symbol=true,
65  const char * prefix=nullptr, const char * suffix=nullptr)
66 {
67  // note: this helper is typically used with utils::expandVar
68  UT_ASSERT(var_name != nullptr);
69  UT_WorkBuffer wb;
70  wb.format("{}{}{}{}", use_symbol ? "$" : "", prefix ? prefix : "", var_name, suffix ? suffix : "");
71  return wb;
72 }
73 
74 static void getBuildCompilerInfo(UT_StringHolder& out_name, exint& out_major, exint& out_minor)
75 {
76 #if defined(_MSC_VER)
77  out_name = "cl";
78  out_major = (_MSC_FULL_VER / 10000000) % 10000;
79  out_minor = (_MSC_FULL_VER / 100000) % 100;
80 
81 #elif defined(__clang__)
82  out_name = "clang";
83  out_major = __clang_major__;
84  out_minor = __clang_minor__;
85 
86 #elif defined(__GNUC__)
87  out_name = "gcc";
88  out_major = __GNUC__;
89  out_minor = __GNUC_MINOR__;
90 #else
91  out_name = "unknown";
92  out_major = NO_VALUE;
93  out_minor = NO_VALUE;
94 #endif
95 }
96 
97 /*
98 Strip some unwanted chars from a variable value string.
99 */
100 static UT_StringHolder cleanupValue(char const * value)
101 {
102  if (value)
103  {
104  static constexpr UT_StringLit kStripables = "\t\n\r";
105  UT_String sval(value);
106  sval.strip(kStripables.asHolder());
107  return sval.c_str();
108  }
109  return UT_StringHolder();
110 }
111 
112 /*
113 Build an array of unset variables found in a given value expression.
114 Update a dependency map to hold dependency information between variables.
115 May returns a list of variables marked as circular dependent.
116 */
117 UT_API extern bool buildVarDependency(
118  UT_StringHolder const& var_name,
119  const char * var_value,
120  UT_StringArray& unset_vars,
121  UT_StringMap<UT_StringSet>& vars_dep_map,
122  UT_StringMap<UT_StringSet>& vars_circ_dep);
123 
124 UT_API extern UT_StringHolder expandVar(const char *arg, bool want_marker);
125 UT_API extern UT_StringHolder makeVarRefPlatform(const char * var);
126 
127 UT_API extern bool isCmdShell();
128 UT_API extern const char *pathSepShell();
129 
130 // Normalizes and expands (optionally) a file path.
131 //
132 // file_path: Path to normalize. We use UT_String to be compatible
133 // with UTnormalizeFilePath which returns the normalized
134 // file path by arg reference.
135 // expand: Expands the content of file_path after the path has been
136 // normalized.
137 // want_marker: If true, expandVar returns `&` if the path is empty.
138 // Mostly used by HOUDINI_PATH like paths.
139 //
140 // always_want_expanded_path: Always keep the result of the expanded
141 // vars with the path even if the content
142 // is empty.
143 // Assumes the input is an environment variable value, potentially
144 // formatted as env var path.
145 UT_API extern void normalizeEnvVarPath(UT_String& file_path, bool want_marker=false, bool always_want_expanded_path=false);
146 UT_API extern void normalizePath(UT_String& file_path, bool want_marker=false, bool always_want_expanded_path=false);
147 UT_API extern void normalizePath(UT_StringHolder& file_path, bool want_marker=false, bool always_want_expanded_path=false);
148 // Returns a new normalized/expanded path
149 UT_API extern UT_StringHolder cnormalizePath(UT_StringHolder const & file_path, bool want_marker=false, bool always_want_expanded_path=false);
150 
151 struct Factory
152 {
153  template <typename T, typename... Args>
154  static UT_SharedPtr<T> make(Args &&... args)
155  {
156  return UTmakeShared<T>(std::forward<Args>(args)...);
157  }
158 };
159 
160 // Helper for handling Houdini version values
161 class HVersion
162 {
163 public:
165  : myMajor(-1)
166  , myMinor(-1)
167  , myBuild(-1)
168  , myPatch(-1)
169  {
170  }
171 
172  int compare( HVersion const & other, bool full=true ) const
173  {
174  if (full)
175  {
176  UT_ASSERT(other.myMajor > -1);
177 
178  // Assign other build + patch with this if not set (-1)
179  int other_minor = myMinor;
180  int other_build = myBuild;
181  int other_patch = myPatch;
182 
183  if (other.myMinor != -1)
184  {
185  other_minor = other.myMinor;
186  }
187 
188  if (other.myBuild != -1)
189  {
190  other_build = other.myBuild;
191  }
192 
193  if (other.myPatch != -1)
194  {
195  other_patch = other.myPatch;
196  }
197 
198  return SYSversionCompare(
199  myMajor, myMinor, myBuild, myPatch, other.myMajor, other_minor, other_build, other_patch);
200  }
201 
202  if (myMajor != other.myMajor)
203  {
204  return myMajor - other.myMajor;
205  }
206 
207  // compare the rest if the other components are provided (!= -1)
208 
209  if (other.myMinor != -1 && myMinor != other.myMinor)
210  {
211  return myMinor - other.myMinor;
212  }
213 
214  if (other.myBuild != -1 && myBuild != other.myBuild)
215  {
216  return myBuild - other.myBuild;
217  }
218  if (other.myPatch != -1 && myPatch != other.myPatch)
219  {
220  return myPatch - other.myPatch;
221  }
222  return 0;
223  }
224 
225  bool operator > (HVersion const & other) const
226  {
227  return compare(other) > 0;
228  }
229 
230  bool operator >= (HVersion const & other) const
231  {
232  return operator>(other) || operator==(other);
233  }
234 
235  bool operator < (HVersion const & other) const
236  {
237  return compare(other) < 0;
238  }
239 
240  bool operator <= (HVersion const & other) const
241  {
242  return operator<(other) || operator==(other);
243  }
244 
245  bool operator == (HVersion const & other) const
246  {
247  return compare(other,false /*full*/) == 0;
248  }
249 
250  static HVersion convert(UT_StringRef const & str)
251  {
252  UT_StringArray tokens;
253  UT_String(str.c_str()).tokenize( tokens, "." );
254 
255  HVersion hver;
256 
257  if (tokens.size() > 4)
258  {
259  // wrong format
260  return hver;
261  }
262  else if (tokens.size()==1)
263  {
264  hver.myMajor = SYSatoi(tokens[0].c_str());
265  }
266  else if (tokens.size()==2)
267  {
268  hver.myMajor = SYSatoi(tokens[0].c_str());
269  hver.myMinor = SYSatoi(tokens[1].c_str());
270  }
271  else if (tokens.size()==3)
272  {
273  hver.myMajor = SYSatoi(tokens[0].c_str());
274  hver.myMinor = SYSatoi(tokens[1].c_str());
275  hver.myBuild = SYSatoi(tokens[2].c_str());
276  }
277  else
278  {
279  hver.myMajor = SYSatoi(tokens[0].c_str());
280  hver.myMinor = SYSatoi(tokens[1].c_str());
281  hver.myBuild = SYSatoi(tokens[2].c_str());
282  hver.myPatch = SYSatoi(tokens[3].c_str());
283  }
284  return hver;
285  }
286 
287  int myMajor;
288  int myMinor;
289  int myBuild;
290  int myPatch;
291 };
292 
293 // Helper for handling Houdini python version with packages
295 {
296 public:
297  // Return the build version name
298  static char const* toString()
299  {
300  static UT_WorkBuffer thePYVersion = []()
301  {
302  UT_WorkBuffer major;
303  major.itoa(PY_MAJOR_VERSION);
304 
305  UT_WorkBuffer minor;
306  minor.itoa(PY_MINOR_VERSION);
307 
308  UT_WorkBuffer pyver;
309  pyver.format("{}{}.{}", "python", major.buffer(), minor.buffer());
310 
311  return pyver;
312  }();
313 
314  return thePYVersion.buffer();
315  }
316 
318  : myMajor(-1)
319  , myMinor(-1)
320  , myMicro(-1)
321  {
322  }
323 
324  int compare( PYVersion const & other) const
325  {
326  if (myMajor != other.myMajor)
327  {
328  return myMajor - other.myMajor;
329  }
330 
331  if (myMinor == -1)
332  {
333  return 0;
334  }
335 
336  // compare the rest if the other components are provided (!= -1)
337 
338  if (other.myMinor != -1 && myMinor != other.myMinor)
339  {
340  return myMinor - other.myMinor;
341  }
342 
343  if (other.myMicro != -1 && myMicro != other.myMicro)
344  {
345  return myMicro - other.myMicro;
346  }
347 
348  return 0;
349  }
350 
351  bool operator > (PYVersion const & other) const
352  {
353  return compare(other) > 0;
354  }
355 
356  bool operator >= (PYVersion const & other) const
357  {
358  return operator>(other) || operator==(other);
359  }
360 
361  bool operator < (PYVersion const & other) const
362  {
363  return compare(other) < 0;
364  }
365 
366  bool operator <= (PYVersion const & other) const
367  {
368  return operator<(other) || operator==(other);
369  }
370 
371  bool operator == (PYVersion const & other) const
372  {
373  return compare(other) == 0;
374  }
375 
376  // Convert a string formatted python version to PYVersion
377  // pyver_str: <python><major>.<minor>.<micro>
378  // Note: minor and micro are optional
379  static PYVersion convert(char const * pyver_str)
380  {
381  PYVersion pyver;
382  UT_String str(pyver_str);
383 
384  if (!str || !str.startsWith("python"))
385  {
386  return pyver;
387  }
388 
389  // Remove the python token
390  str.eraseHead(6);
391 
392  UT_StringArray tokens;
393  str.tokenize(tokens, ".");
394 
395  if (tokens.size() > 3)
396  {
397  // wrong format
398  return pyver;
399  }
400  else if (tokens.size()==1)
401  {
402  pyver.myMajor = SYSatoi(tokens[0].c_str());
403  }
404  else if (tokens.size()==2)
405  {
406  pyver.myMajor = SYSatoi(tokens[0].c_str());
407  pyver.myMinor = SYSatoi(tokens[1].c_str());
408  }
409  else if (tokens.size()==3)
410  {
411  pyver.myMajor = SYSatoi(tokens[0].c_str());
412  pyver.myMinor = SYSatoi(tokens[1].c_str());
413  pyver.myMicro = SYSatoi(tokens[2].c_str());
414  }
415  return pyver;
416  }
417 
418  static void getVersion(PYVersion& pyver)
419  {
420  pyver.myMajor = PY_MAJOR_VERSION;
421  pyver.myMinor = PY_MINOR_VERSION;
422  pyver.myMicro = PY_MICRO_VERSION;
423  }
424 
425  int myMajor;
426  int myMinor;
427  int myMicro;
428 };
429 
430 // Helper for handling the compiler version used for building Houdini.
432 {
433 public:
435  : myMajor(NO_VALUE)
436  , myMinor(NO_VALUE)
437  {
438  }
439 
440  int compare(HPlatformBuildVersion const& other) const
441  {
442  if (myName != other.myName)
443  {
444  return -1;
445  }
446 
447  if (myMajor != NO_VALUE && other.myMajor != NO_VALUE && myMajor != other.myMajor)
448  {
449  return myMajor - other.myMajor;
450  }
451 
452  if (myMinor != NO_VALUE && other.myMinor != NO_VALUE && myMinor != other.myMinor)
453  {
454  return myMinor - other.myMinor;
455  }
456 
457  return 0;
458  }
459 
460  bool operator > (HPlatformBuildVersion const& other) const
461  {
462  return compare(other) > 0;
463  }
464 
465  bool operator >= (HPlatformBuildVersion const& other) const
466  {
467  return operator>(other) || operator==(other);
468  }
469 
470  bool operator < (HPlatformBuildVersion const& other) const
471  {
472  return compare(other) < 0;
473  }
474 
475  bool operator <= (HPlatformBuildVersion const& other) const
476  {
477  return operator<(other) || operator==(other);
478  }
479 
480  bool operator == (HPlatformBuildVersion const& other) const
481  {
482  return compare(other) == 0;
483  }
484 
485  // Convert a string formatted platform build version to HPlatformBuildVersion
486  // ver_str: <compiler name>.<major>.<minor>
487  static HPlatformBuildVersion convert(char const* ver_str)
488  {
489  HPlatformBuildVersion pbver;
490 
491  if (!ver_str || !strlen(ver_str))
492  {
493  return pbver;
494  }
495 
496  UT_StringArray tokens;
497  UT_String ut_ver_str(ver_str);
498  ut_ver_str.tokenize(tokens, ".");
499 
500  if (tokens.size() < 1 || tokens.size() > 3)
501  {
502  // wrong format
503  return pbver;
504  }
505 
506  if (tokens.size()==1)
507  {
508  pbver.myName = tokens[0].c_str();
509  }
510  else if (tokens.size()==2)
511  {
512  pbver.myName = tokens[0].c_str();
513  pbver.myMajor = SYSatoi(tokens[1].c_str());
514  }
515  else
516  {
517  pbver.myName = tokens[0].c_str();
518  pbver.myMajor = SYSatoi(tokens[1].c_str());
519  pbver.myMinor = SYSatoi(tokens[2].c_str());
520  }
521 
522  return pbver;
523  }
524 
525  void getVersion(UT_StringHolder& out_name, exint& out_major, exint& out_minor)
526  {
527  out_name = myName;
528  out_major = myMajor;
529  out_minor = myMinor;
530  }
531 
532  static
534  {
535  getBuildCompilerInfo(out_version.myName, out_version.myMajor, out_version.myMinor);
536  }
537 
538  // Build the version string. Supported formats:
539  // name.major.minor
540  // name.major
541  // name
543  {
544  if (myName.isEmpty())
545  {
546  static UT_StringHolder unknown("unknown");
547  return unknown;
548  }
549 
550  UT_WorkBuffer ver;
551  if (myMajor != NO_VALUE && myMinor != NO_VALUE)
552  ver.format("{}.{}.{}", myName, myMajor, myMinor);
553  else if (myMajor != NO_VALUE && myMinor == NO_VALUE)
554  ver.format("{}.{}", myName, myMajor);
555  else
556  ver.format("{}", myName);
557  return ver;
558  }
559 
563 };
564 
565 // Encapsulates variant values used by UT_Package
566 class Value
567 {
568 public:
570 
571  Value() = default;
572 
573  explicit Value(const char *value)
574  {
575  set(value);
576  }
577 
578  explicit Value(UT_StringRef const & value)
579  {
580  if (value.isstring())
581  {
582  myValue = std::string(value.c_str(), value.length());
583  }
584  else
585  {
586  myValue = std::string();
587  }
588  }
589 
590  explicit Value(fpreal64 value)
591  {
592  myValue = value;
593  }
594 
595  explicit Value(int64 value)
596  {
597  myValue = value;
598  }
599 
600  explicit Value(bool value)
601  {
602  myValue = value;
603  }
604 
605  explicit Value(HVersion value)
606  {
607  myValue = value;
608  }
609 
610  explicit Value(PYVersion value)
611  {
612  myValue = value;
613  }
614 
615  explicit Value(HPlatformBuildVersion value)
616  {
617  myValue = value;
618  }
619 
620  hboost::any const & value() const
621  {
622  return myValue;
623  }
624 
625  void set(const char *value)
626  {
627  if (value)
628  {
629  myValue = std::string(value, strlen(value));
630  }
631  else
632  {
633  myValue = std::string();
634  }
635  }
636 
637  void set(fpreal64 value)
638  {
639  myValue = value;
640  }
641 
642  void set(int64 value)
643  {
644  myValue = value;
645  }
646 
647  void set(bool value)
648  {
649  myValue = value;
650  }
651 
652  void set(HVersion value)
653  {
654  myValue = value;
655  }
656 
657  void set(PYVersion value)
658  {
659  myValue = value;
660  }
661 
663  {
664  myValue = value;
665  }
666 
668  {
669  return toWorkBuffer().buffer();
670  }
671 
673  {
674  UT_WorkBuffer wb;
675  if (isA<fpreal64>())
676  {
677  wb.format("{}", hboost::any_cast<fpreal64>(myValue));
678  }
679  else if (isA<int64>())
680  {
681  wb.format("{}", hboost::any_cast<int64>(myValue));
682  }
683  else if (isA<bool>())
684  {
685  wb.format("{}", hboost::any_cast<bool>(myValue) ? "1" : "0");
686  }
687  else if (isA<std::string>())
688  {
689  wb.format("{}",hboost::any_cast<std::string>(myValue));
690  }
691  else if (isA<HVersion>())
692  {
693  auto && hver = hboost::any_cast<HVersion>(myValue);
694  wb.format("{}.{}.{}.{}",hver.myMajor,hver.myMinor,hver.myBuild,hver.myPatch);
695  }
696  else if (isA<PYVersion>())
697  {
698  auto && pyver = hboost::any_cast<PYVersion>(myValue);
699  wb.format("python{}.{}", pyver.myMajor,pyver.myMinor);
700  }
701  else if (isA<HPlatformBuildVersion>())
702  {
703  auto&& hbc_ver = hboost::any_cast<HPlatformBuildVersion>(myValue);
704  wb = hbc_ver.toString();
705  }
706  else
707  {
708  UT_ASSERT(!"Unknown type in UT_Package::utils::Value");
709  }
710 
711  return wb;
712  }
713 
714  template <typename T>
715  T const & get() const
716  {
717  return hboost::any_cast<T const &>(myValue);
718  }
719 
720  template <typename T>
721  bool isA() const
722  {
723  return hboost::typeindex::type_id<T>() == myValue.type();
724  }
725 
726  bool valid() const
727  {
728  return !myValue.empty();
729  }
730 
731  bool isEqual(utils::Value const & other, bool ignore_case=false) const
732  {
733  if (isA<std::string>() && other.isA<std::string>())
734  {
735  if (ignore_case)
736  {
737  auto && lhs = hboost::any_cast<std::string>(myValue);
738  auto && rhs = hboost::any_cast<std::string>(other.value());
739  return compareIgnoreCase(lhs, rhs);
740  }
741  else
742  {
743  return get<std::string>() == other.get<std::string>();
744  }
745  }
746 
747  if (isA<int64>() && other.isA<int64>())
748  {
749  return get<int64>() == other.get<int64>();
750  }
751 
752  if (isA<fpreal64>() && other.isA<fpreal64>())
753  {
754  return get<fpreal64>() == other.get<fpreal64>();
755  }
756 
757  if (isA<bool>() && other.isA<bool>())
758  {
759  return get<bool>() == other.get<bool>();
760  }
761 
762  if (isA<HVersion>() && other.isA<HVersion>())
763  {
764  return get<HVersion>() == other.get<HVersion>();
765  }
766 
767  if (isA<HVersion>() && other.isA<std::string>())
768  {
769  HVersion hver = HVersion::convert(other.get<std::string>().c_str());
770  return get<HVersion>() == hver;
771  }
772 
773  if (isA<std::string>() && other.isA<HVersion>())
774  {
775  HVersion hver = HVersion::convert(get<std::string>().c_str());
776  return hver == other.get<HVersion>();
777  }
778 
779  if (isA<PYVersion>() && other.isA<PYVersion>())
780  {
781  return get<PYVersion>() == other.get<PYVersion>();
782  }
783 
784  if (isA<PYVersion>() && other.isA<std::string>())
785  {
786  PYVersion pyver = PYVersion::convert(other.get<std::string>().c_str());
787  return get<PYVersion>() == pyver;
788  }
789 
790  if (isA<std::string>() && other.isA<PYVersion>())
791  {
792  PYVersion pyver = PYVersion::convert(get<std::string>().c_str());
793  return pyver == other.get<PYVersion>();
794  }
795 
796  if (isA<HPlatformBuildVersion>() && other.isA<HPlatformBuildVersion>())
797  {
798  return get<HPlatformBuildVersion>() == other.get<HPlatformBuildVersion>();
799  }
800 
801  if (isA<HPlatformBuildVersion>() && other.isA<std::string>())
802  {
804  return get<HPlatformBuildVersion>() == pbver;
805  }
806 
807  if (isA<std::string>() && other.isA<HPlatformBuildVersion>())
808  {
809  HPlatformBuildVersion pbver = HPlatformBuildVersion::convert(get<std::string>().c_str());
810  return pbver == other.get<HPlatformBuildVersion>();
811  }
812 
813  throw std::runtime_error("utils::Value::isEqual: unsupported type");
814  }
815 
816  bool isGreater(utils::Value const & other) const
817  {
818  if ( isA<std::string>() && other.isA<std::string>() )
819  {
820  return get<std::string>() > other.get<std::string>();
821  }
822 
823  if (isA<HVersion>() && other.isA<HVersion>())
824  {
825  return get<HVersion>() > other.get<HVersion>();
826  }
827 
828  if (isA<HVersion>() && other.isA<std::string>())
829  {
830  HVersion hver = HVersion::convert(other.get<std::string>().c_str());
831  return get<HVersion>() > hver;
832  }
833 
834  if (isA<std::string>() && other.isA<HVersion>())
835  {
836  HVersion hver = HVersion::convert(get<std::string>().c_str());
837  return hver > other.get<HVersion>();
838  }
839 
840  if (isA<PYVersion>() && other.isA<PYVersion>())
841  {
842  return get<PYVersion>() > other.get<PYVersion>();
843  }
844 
845  if (isA<PYVersion>() && other.isA<std::string>())
846  {
847  PYVersion pyver = PYVersion::convert(other.get<std::string>().c_str());
848  return get<PYVersion>() > pyver;
849  }
850 
851  if (isA<std::string>() && other.isA<PYVersion>())
852  {
853  PYVersion pyver = PYVersion::convert(get<std::string>().c_str());
854  return pyver > other.get<PYVersion>();
855  }
856 
857  if (isA<HPlatformBuildVersion>() && other.isA<HPlatformBuildVersion>())
858  {
859  return get<HPlatformBuildVersion>() > other.get<HPlatformBuildVersion>();
860  }
861 
862  if (isA<HPlatformBuildVersion>() && other.isA<std::string>())
863  {
865  return get<HPlatformBuildVersion>() > pbver;
866  }
867 
868  if (isA<std::string>() && other.isA<HPlatformBuildVersion>())
869  {
870  HPlatformBuildVersion pbver = HPlatformBuildVersion::convert(get<std::string>().c_str());
871  return pbver > other.get<HPlatformBuildVersion>();
872  }
873 
874  if ( isA<std::string>() || other.isA<std::string>() )
875  {
876  throw std::runtime_error("utils::Value::isGreater: unsupported types");
877  }
878 
879  return get<fpreal64>() > other.get<fpreal64>();
880  }
881 
882  bool isGreaterEqual(utils::Value const & other) const
883  {
884  return isGreater(other) || isEqual(other);
885  }
886 
887  bool isLess(utils::Value const & other) const
888  {
889  if ( isA<std::string>() && other.isA<std::string>() )
890  {
891  return get<std::string>() < other.get<std::string>();
892  }
893 
894  if (isA<HVersion>() && other.isA<HVersion>())
895  {
896  return get<HVersion>() < other.get<HVersion>();
897  }
898 
899  if (isA<HVersion>() && other.isA<std::string>())
900  {
901  HVersion hver = HVersion::convert(other.get<std::string>().c_str());
902  return get<HVersion>() < hver;
903  }
904 
905  if (isA<std::string>() && other.isA<HVersion>())
906  {
907  HVersion hver = HVersion::convert(get<std::string>().c_str());
908  return hver < other.get<HVersion>();
909  }
910 
911  if (isA<PYVersion>() && other.isA<PYVersion>())
912  {
913  return get<PYVersion>() < other.get<PYVersion>();
914  }
915 
916  if (isA<PYVersion>() && other.isA<std::string>())
917  {
918  PYVersion pyver = PYVersion::convert(other.get<std::string>().c_str());
919  return get<PYVersion>() < pyver;
920  }
921 
922  if (isA<std::string>() && other.isA<PYVersion>())
923  {
924  PYVersion pyver = PYVersion::convert(get<std::string>().c_str());
925  return pyver < other.get<PYVersion>();
926  }
927 
928  if (isA<HPlatformBuildVersion>() && other.isA<HPlatformBuildVersion>())
929  {
930  return get<HPlatformBuildVersion>() < other.get<HPlatformBuildVersion>();
931  }
932 
933  if (isA<HPlatformBuildVersion>() && other.isA<std::string>())
934  {
936  return get<HPlatformBuildVersion>() < pbver;
937  }
938 
939  if (isA<std::string>() && other.isA<HPlatformBuildVersion>())
940  {
941  HPlatformBuildVersion pbver = HPlatformBuildVersion::convert(get<std::string>().c_str());
942  return pbver < other.get<HPlatformBuildVersion>();
943  }
944 
945  if ( isA<std::string>() || other.isA<std::string>() )
946  {
947  throw std::runtime_error("utils::Value::isLess: unsupported types");
948  }
949 
950  return get<fpreal64>() < other.get<fpreal64>();
951  }
952 
953  bool isLessEqual(utils::Value const & other) const
954  {
955  return isLess(other) || isEqual(other);
956  }
957 
958  // Substiture all occurances of find with replace_with
959  bool substitute(char const* find, char const* replace_with)
960  {
961  if (valid() && isA<std::string>())
962  {
963  auto && to_replace = get<std::string>();
964  UT_WorkBuffer wb(to_replace.c_str());
965  if (wb.substitute(find, replace_with))
966  {
967  set(wb.buffer());
968  return true;
969  }
970  }
971  return false;
972  }
973 
974 private:
975  bool compareIgnoreCase(std::string & s1, std::string & s2) const
976  {
977  return ((s1.size() == s2.size()) &&
978  std::equal(s1.begin(), s1.end(), s2.begin(),
979  [](char & c1, char & c2)
980  {
981  return (c1 == c2 || std::toupper(c1) == std::toupper(c2));
982  }
983  ));
984  }
985  hboost::any myValue;
986 }; // Value
987 
988 // Loggger to hold warning/errors/info messages
989 class Logger
990 {
991 public:
994 
995  enum class Flags : unsigned
996  {
997  all,
998  info,
999  warning,
1000  error
1001  };
1002 
1004  : myHasErrorFlag(false)
1005  , myLog(&myDefaultLog)
1006  , myVerboseFlag(false)
1007  {
1008  }
1009 
1010  void setAsVerbose(bool flag)
1011  {
1012  myVerboseFlag = flag;
1013  }
1014 
1015  bool verbose() const
1016  {
1017  return myVerboseFlag;
1018  }
1019 
1020  void error(char const* msg)
1021  {
1022  addToBuffer(klog_error.asHolder(), msg);
1023  if (msg)
1024  {
1025  myHasErrorFlag = true;
1026  }
1027  }
1028 
1029  template< typename ...Args >
1030  void error(char const* msg, Args&&... args)
1031  {
1032  addToBuffer(klog_error.asHolder(), formatMsg(msg, std::forward<Args>(args)...));
1033  if (msg)
1034  {
1035  myHasErrorFlag = true;
1036  }
1037  }
1038 
1039  void info(char const* msg)
1040  {
1041  if (!myVerboseFlag)
1042  {
1043  return;
1044  }
1045  addToBuffer(klog_info.asHolder(), msg);
1046  }
1047 
1048  template< typename ...Args >
1049  void info(char const* msg, Args&&... args)
1050  {
1051  if (!myVerboseFlag)
1052  {
1053  return;
1054  }
1055  addToBuffer(klog_info.asHolder(), formatMsg(msg, std::forward<Args>(args)...));
1056  }
1057 
1058  void message(char const* msg)
1059  {
1060  if (!myVerboseFlag)
1061  {
1062  return;
1063  }
1064  addToBuffer(nullptr, msg);
1065  }
1066 
1067  template< typename ...Args >
1068  void message(char const* msg, Args&&... args)
1069  {
1070  if (!myVerboseFlag)
1071  {
1072  return;
1073  }
1074  addToBuffer(nullptr, formatMsg(msg, std::forward<Args>(args)...));
1075  }
1076 
1077  void warning(char const* msg)
1078  {
1079  addToBuffer(klog_warning.asHolder(), msg);
1080  }
1081 
1082  template< typename ...Args >
1083  void warning(char const* msg, Args&&... args)
1084  {
1085  addToBuffer(klog_warning.asHolder(), formatMsg(msg, std::forward<Args>(args)...));
1086  }
1087 
1088  void clear()
1089  {
1090  myDefaultLog.clear();
1091  myEntryMap.clear();
1092  myEntryArray.clear();
1093  myErrorArray.clear();
1094  myWarningArray.clear();
1095  myHasErrorFlag = false;
1096  }
1097 
1099  {
1100  myErrorArray.clear();
1101  myHasErrorFlag = false;
1102  }
1103 
1104  void toStream(std::ostream &os) const
1105  {
1106  for (auto && entry : myEntryArray)
1107  {
1108  os << entry.c_str() << std::endl;
1109  auto && it = myEntryMap.find(entry);
1110  os << it->second.c_str() << std::endl;
1111  }
1112 
1113  if (myDefaultLog)
1114  {
1115  os << myDefaultLog.c_str() << std::endl;
1116  }
1117  }
1118 
1119  UT_StringHolder toString(bool header=true) const
1120  {
1121  UT_OStringStream ss;
1122  toStream(ss);
1124  if (header && myVerboseFlag)
1125  {
1126  log += "= = = Houdini Package log = = =\n";
1127  }
1128 
1129  log += ss.str().buffer();
1130 
1131  if (header && myVerboseFlag)
1132  {
1133  log += "= = = = = = = = = = = = = = = =\n";
1134  }
1135  return log;
1136  }
1137 
1138  UT_StringArray const & errors() const
1139  {
1140  return myErrorArray;
1141  }
1142 
1143  UT_StringArray const & warnings() const
1144  {
1145  return myWarningArray;
1146  }
1147 
1148  void log(char const* title, Flags flags=Flags::all) const
1149  {
1150  if (flags == Flags::all)
1151  {
1152  std::cout << title << std::endl;
1153  toStream(std::cout);
1154  }
1155  else if (myHasErrorFlag && flags == Flags::error)
1156  {
1157  std::cerr << title << std::endl;
1158  toStream(std::cerr);
1159  }
1160  }
1161 
1162  void start(char const * entry)
1163  {
1164  if (!entry)
1165  {
1166  // global logging
1167  myLog = &myDefaultLog;
1168  return;
1169  }
1170 
1171  // logging done per entry
1172  if (!myEntryMap.count(entry))
1173  {
1174  myEntryMap[entry] = UT_StringHolder();
1175  myEntryArray.append(entry);
1176  }
1177  myLog = &myEntryMap[entry];
1178  }
1179 
1180  bool hasErrors() const
1181  {
1182  return myHasErrorFlag;
1183  }
1184 
1185  void append(Logger const & logger)
1186  {
1187  UT_OStringStream ss;
1188  logger.toStream(ss);
1189 
1190  UT_WorkBuffer wb;
1191  wb += ss.str().buffer();
1192 
1193  if (wb.buffer())
1194  {
1195  buffer() += wb.buffer();
1196  }
1197  }
1198 
1199 private:
1200  template< typename ...Args >
1201  UT_StringHolder formatMsg( const char* format, Args &&... args )
1202  {
1203  UT_WorkBuffer wb;
1204  wb.format(format, args...);
1205  return wb;
1206  }
1207 
1208  void addToBuffer(const char* prefix, const char* msg)
1209  {
1210  if (!msg || !strlen(msg))
1211  {
1212  return;
1213  }
1214 
1215  if (prefix)
1216  {
1217  buffer() += prefix;
1218  buffer() += ": ";
1219  }
1220  buffer() += msg;
1221  buffer() += "\n";
1222 
1223  if ( msg && prefix && klog_error.asHolder().equal(prefix))
1224  {
1225  myErrorArray.append(msg);
1226  }
1227  else if ( msg && prefix && klog_warning.asHolder().equal(prefix))
1228  {
1229  myWarningArray.append(msg);
1230  }
1231  }
1232 
1233  UT_StringHolder & buffer()
1234  {
1235  return *myLog;
1236  }
1237 
1238  UT_StringHolder const & buffer() const
1239  {
1240  return *myLog;
1241  }
1242 
1243  EntryArray myEntryArray;
1244  EntryMap myEntryMap;
1245  UT_StringHolder* myLog;
1246  UT_StringHolder myDefaultLog;
1247  UT_StringArray myWarningArray;
1248  UT_StringArray myErrorArray;
1249  bool myHasErrorFlag;
1250  bool myVerboseFlag;
1251 }; // Logger
1252 
1253 } // utils
1254 } // UT_Package
1255 
1256 #endif // UT_PackageUtils_H
bool isGreaterEqual(utils::Value const &other) const
bool operator>=(PYVersion const &other) const
std::string ignore_case(std::string item)
Helper function to allow ignore_case to be passed to IsMember or Transform.
Definition: CLI11.h:3456
GLbitfield flags
Definition: glcorearb.h:1596
UT_API void normalizePath(UT_String &file_path, bool want_marker=false, bool always_want_expanded_path=false)
bool isGreater(utils::Value const &other) const
bool operator>(HVersion const &other) const
UT_API bool buildVarDependency(UT_StringHolder const &var_name, const char *var_value, UT_StringArray &unset_vars, UT_StringMap< UT_StringSet > &vars_dep_map, UT_StringMap< UT_StringSet > &vars_circ_dep)
UT_StringHolder toString(bool header=true) const
void start(char const *entry)
#define PATH_SEP_STRING
Definition: hpath.h:33
void set(HVersion value)
bool operator>=(HVersion const &other) const
SYS_FORCE_INLINE void clear()
bool operator<=(PYVersion const &other) const
int compare(HVersion const &other, bool full=true) const
GLsizei const GLchar *const * string
Definition: glcorearb.h:814
void getVersion(UT_StringHolder &out_name, exint &out_major, exint &out_minor)
bool operator<(HVersion const &other) const
bool isEmpty() const
Same as !isstring()
UT_API UT_StringHolder makeVarRefPlatform(const char *var)
int64 exint
Definition: SYS_Types.h:125
bool operator==(PYVersion const &other) const
static char const * toString()
#define SYS_INT64_MAX
Definition: SYS_Types.h:176
SYS_FORCE_INLINE const char * buffer() const
void info(char const *msg, Args &&...args)
int compare(PYVersion const &other) const
int substitute(const char *find, const char *replacement, int count=-1)
An output stream object that owns its own string buffer storage.
void message(char const *msg)
IMATH_HOSTDEVICE constexpr bool equal(T1 a, T2 b, T3 t) IMATH_NOEXCEPT
Definition: ImathFun.h:105
#define UT_API
Definition: UT_API.h:14
bool equal(const UT_StringRef &str, bool ignore_case=false) const
void message(char const *msg, Args &&...args)
bool substitute(char const *find, char const *replace_with)
#define PATH_SEP_CHAR
Definition: hpath.h:32
bool operator<=(HVersion const &other) const
UT_StringArray const & errors() const
void clear()
Definition: UT_Map.h:184
auto arg(const Char *name, const T &arg) -> detail::named_arg< Char, T >
Definition: core.h:1736
static void getVersion(PYVersion &pyver)
const UT_WorkBuffer & str()
Returns a read-only reference to the underlying UT_WorkBuffer.
exint size() const
Definition: UT_Array.h:646
void toStream(std::ostream &os) const
bool operator==(HPlatformBuildVersion const &other) const
double fpreal64
Definition: SYS_Types.h:201
void error(char const *msg, Args &&...args)
UT_StringHolder toString() const
void set(PYVersion value)
Definition: core.h:760
void set(HPlatformBuildVersion value)
int tokenize(char *argv[], int max_args, char separator)
Definition: UT_String.h:842
bool any(const vbool4 &v)
Definition: simd.h:3468
exint length() const
std::shared_ptr< T > UT_SharedPtr
Wrapper around std::shared_ptr.
Definition: UT_SharedPtr.h:36
UT_API const char * pathSepShell()
UT_WorkBuffer toWorkBuffer() const
UT_StringArray const & warnings() const
bool isLess(utils::Value const &other) const
hboost::any const & value() const
GLint GLint GLsizei GLint GLenum format
Definition: glcorearb.h:108
Value(UT_StringRef const &value)
static UT_SharedPtr< T > make(Args &&...args)
static void getVersion(HPlatformBuildVersion &out_version)
UT_API UT_StringHolder expandVar(const char *arg, bool want_marker)
static PYVersion convert(char const *pyver_str)
void set(const char *value)
long long int64
Definition: SYS_Types.h:116
bool isEqual(utils::Value const &other, bool ignore_case=false) const
SYS_FORCE_INLINE const char * c_str() const
void error(char const *msg)
void warning(char const *msg, Args &&...args)
int eraseHead(int len)
Definition: UT_String.h:1098
UT_API UT_StringHolder cnormalizePath(UT_StringHolder const &file_path, bool want_marker=false, bool always_want_expanded_path=false)
constexpr UT_StringLit klog_error
exint append()
Definition: UT_Array.h:142
Definition: oidn.hpp:29
bool operator==(HVersion const &other) const
void append(Logger const &logger)
UT_StringMap< UT_StringHolder > EntryMap
UT_API void normalizeEnvVarPath(UT_String &file_path, bool want_marker=false, bool always_want_expanded_path=false)
size_t format(const char *fmt, const Args &...args)
int compare(HPlatformBuildVersion const &other) const
constexpr UT_StringLit klog_info
bool operator<(HPlatformBuildVersion const &other) const
void log(char const *title, Flags flags=Flags::all) const
void itoa(int64 i)
UT_API bool isCmdShell()
bool operator<(PYVersion const &other) const
constexpr UT_StringLit klog_warning
SYS_FORCE_INLINE const UT_StringHolder & asHolder() const
bool operator>=(HPlatformBuildVersion const &other) const
bool operator>(PYVersion const &other) const
Value(const char *value)
**If you just want to fire and args
Definition: thread.h:609
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
Definition: core.h:1131
void info(char const *msg)
void clear()
Resets list to an empty list.
Definition: UT_Array.h:729
static HVersion convert(UT_StringRef const &str)
bool startsWith(const UT_StringView &prefix, bool case_sensitive=true) const
void warning(char const *msg)
T const & get() const
bool operator<=(HPlatformBuildVersion const &other) const
void set(fpreal64 value)
bool isLessEqual(utils::Value const &other) const
constexpr exint NO_VALUE
Value(HPlatformBuildVersion value)
bool operator>(HPlatformBuildVersion const &other) const
SYS_FORCE_INLINE bool isstring() const
static HPlatformBuildVersion convert(char const *ver_str)
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr &out) -> bool
Definition: core.h:2089