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.c_str();
548  }
549 
550  UT_WorkBuffer ver;
551 
552  if (myMajor != NO_VALUE && myMinor != NO_VALUE)
553  {
554  ver.format("{}.{}.{}", myName, myMajor, myMinor);
555  }
556  else if (myMajor != NO_VALUE && myMinor == NO_VALUE)
557  {
558  ver.format("{}.{}", myName, myMajor);
559  }
560  else
561  {
562  ver.format("{}", myName);
563  }
564  return ver.buffer();
565  }
566 
570 };
571 
572 // Encapsulates variant values used by UT_Package
573 class Value
574 {
575 public:
577 
578  Value() = default;
579 
580  explicit Value(const char *value)
581  {
582  set(value);
583  }
584 
585  explicit Value(UT_StringRef const & value)
586  {
587  if (value.isstring())
588  {
589  myValue = std::string(value.c_str(), value.length());
590  }
591  else
592  {
593  myValue = std::string();
594  }
595  }
596 
597  explicit Value(fpreal64 value)
598  {
599  myValue = value;
600  }
601 
602  explicit Value(int64 value)
603  {
604  myValue = value;
605  }
606 
607  explicit Value(bool value)
608  {
609  myValue = value;
610  }
611 
612  explicit Value(HVersion value)
613  {
614  myValue = value;
615  }
616 
617  explicit Value(PYVersion value)
618  {
619  myValue = value;
620  }
621 
622  explicit Value(HPlatformBuildVersion value)
623  {
624  myValue = value;
625  }
626 
627  hboost::any const & value() const
628  {
629  return myValue;
630  }
631 
632  void set(const char *value)
633  {
634  if (value)
635  {
636  myValue = std::string(value, strlen(value));
637  }
638  else
639  {
640  myValue = std::string();
641  }
642  }
643 
644  void set(fpreal64 value)
645  {
646  myValue = value;
647  }
648 
649  void set(int64 value)
650  {
651  myValue = value;
652  }
653 
654  void set(bool value)
655  {
656  myValue = value;
657  }
658 
659  void set(HVersion value)
660  {
661  myValue = value;
662  }
663 
664  void set(PYVersion value)
665  {
666  myValue = value;
667  }
668 
670  {
671  myValue = value;
672  }
673 
675  {
676  return toWorkBuffer().buffer();
677  }
678 
680  {
681  UT_WorkBuffer wb;
682  if (isA<fpreal64>())
683  {
684  wb.format("{}", hboost::any_cast<fpreal64>(myValue));
685  }
686  else if (isA<int64>())
687  {
688  wb.format("{}", hboost::any_cast<int64>(myValue));
689  }
690  else if (isA<bool>())
691  {
692  wb.format("{}", hboost::any_cast<bool>(myValue) ? "1" : "0");
693  }
694  else if (isA<std::string>())
695  {
696  wb.format("{}",hboost::any_cast<std::string>(myValue));
697  }
698  else if (isA<HVersion>())
699  {
700  auto && hver = hboost::any_cast<HVersion>(myValue);
701  wb.format("{}.{}.{}.{}",hver.myMajor,hver.myMinor,hver.myBuild,hver.myPatch);
702  }
703  else if (isA<PYVersion>())
704  {
705  auto && pyver = hboost::any_cast<PYVersion>(myValue);
706  wb.format("python{}.{}", pyver.myMajor,pyver.myMinor);
707  }
708  else if (isA<HPlatformBuildVersion>())
709  {
710  auto&& hbc_ver = hboost::any_cast<HPlatformBuildVersion>(myValue);
711  wb = hbc_ver.toString();
712  }
713  else
714  {
715  UT_ASSERT(!"Unknown type in UT_Package::utils::Value");
716  }
717 
718  return wb;
719  }
720 
721  template <typename T>
722  T const & get() const
723  {
724  return hboost::any_cast<T const &>(myValue);
725  }
726 
727  template <typename T>
728  bool isA() const
729  {
730  return hboost::typeindex::type_id<T>() == myValue.type();
731  }
732 
733  bool valid() const
734  {
735  return !myValue.empty();
736  }
737 
738  bool isEqual(utils::Value const & other, bool ignore_case=false) const
739  {
740  if (isA<std::string>() && other.isA<std::string>())
741  {
742  if (ignore_case)
743  {
744  auto && lhs = hboost::any_cast<std::string>(myValue);
745  auto && rhs = hboost::any_cast<std::string>(other.value());
746  return compareIgnoreCase(lhs, rhs);
747  }
748  else
749  {
750  return get<std::string>() == other.get<std::string>();
751  }
752  }
753 
754  if (isA<int64>() && other.isA<int64>())
755  {
756  return get<int64>() == other.get<int64>();
757  }
758 
759  if (isA<fpreal64>() && other.isA<fpreal64>())
760  {
761  return get<fpreal64>() == other.get<fpreal64>();
762  }
763 
764  if (isA<bool>() && other.isA<bool>())
765  {
766  return get<bool>() == other.get<bool>();
767  }
768 
769  if (isA<HVersion>() && other.isA<HVersion>())
770  {
771  return get<HVersion>() == other.get<HVersion>();
772  }
773 
774  if (isA<HVersion>() && other.isA<std::string>())
775  {
776  HVersion hver = HVersion::convert(other.get<std::string>().c_str());
777  return get<HVersion>() == hver;
778  }
779 
780  if (isA<std::string>() && other.isA<HVersion>())
781  {
782  HVersion hver = HVersion::convert(get<std::string>().c_str());
783  return hver == other.get<HVersion>();
784  }
785 
786  if (isA<PYVersion>() && other.isA<PYVersion>())
787  {
788  return get<PYVersion>() == other.get<PYVersion>();
789  }
790 
791  if (isA<PYVersion>() && other.isA<std::string>())
792  {
793  PYVersion pyver = PYVersion::convert(other.get<std::string>().c_str());
794  return get<PYVersion>() == pyver;
795  }
796 
797  if (isA<std::string>() && other.isA<PYVersion>())
798  {
799  PYVersion pyver = PYVersion::convert(get<std::string>().c_str());
800  return pyver == other.get<PYVersion>();
801  }
802 
803  if (isA<HPlatformBuildVersion>() && other.isA<HPlatformBuildVersion>())
804  {
805  return get<HPlatformBuildVersion>() == other.get<HPlatformBuildVersion>();
806  }
807 
808  if (isA<HPlatformBuildVersion>() && other.isA<std::string>())
809  {
811  return get<HPlatformBuildVersion>() == pbver;
812  }
813 
814  if (isA<std::string>() && other.isA<HPlatformBuildVersion>())
815  {
816  HPlatformBuildVersion pbver = HPlatformBuildVersion::convert(get<std::string>().c_str());
817  return pbver == other.get<HPlatformBuildVersion>();
818  }
819 
820  throw std::runtime_error("utils::Value::isEqual: unsupported type");
821  }
822 
823  bool isGreater(utils::Value const & other) const
824  {
825  if ( isA<std::string>() && other.isA<std::string>() )
826  {
827  return get<std::string>() > other.get<std::string>();
828  }
829 
830  if (isA<HVersion>() && other.isA<HVersion>())
831  {
832  return get<HVersion>() > other.get<HVersion>();
833  }
834 
835  if (isA<HVersion>() && other.isA<std::string>())
836  {
837  HVersion hver = HVersion::convert(other.get<std::string>().c_str());
838  return get<HVersion>() > hver;
839  }
840 
841  if (isA<std::string>() && other.isA<HVersion>())
842  {
843  HVersion hver = HVersion::convert(get<std::string>().c_str());
844  return hver > other.get<HVersion>();
845  }
846 
847  if (isA<PYVersion>() && other.isA<PYVersion>())
848  {
849  return get<PYVersion>() > other.get<PYVersion>();
850  }
851 
852  if (isA<PYVersion>() && other.isA<std::string>())
853  {
854  PYVersion pyver = PYVersion::convert(other.get<std::string>().c_str());
855  return get<PYVersion>() > pyver;
856  }
857 
858  if (isA<std::string>() && other.isA<PYVersion>())
859  {
860  PYVersion pyver = PYVersion::convert(get<std::string>().c_str());
861  return pyver > other.get<PYVersion>();
862  }
863 
864  if (isA<HPlatformBuildVersion>() && other.isA<HPlatformBuildVersion>())
865  {
866  return get<HPlatformBuildVersion>() > other.get<HPlatformBuildVersion>();
867  }
868 
869  if (isA<HPlatformBuildVersion>() && other.isA<std::string>())
870  {
872  return get<HPlatformBuildVersion>() > pbver;
873  }
874 
875  if (isA<std::string>() && other.isA<HPlatformBuildVersion>())
876  {
877  HPlatformBuildVersion pbver = HPlatformBuildVersion::convert(get<std::string>().c_str());
878  return pbver > other.get<HPlatformBuildVersion>();
879  }
880 
881  if ( isA<std::string>() || other.isA<std::string>() )
882  {
883  throw std::runtime_error("utils::Value::isGreater: unsupported types");
884  }
885 
886  return get<fpreal64>() > other.get<fpreal64>();
887  }
888 
889  bool isGreaterEqual(utils::Value const & other) const
890  {
891  return isGreater(other) || isEqual(other);
892  }
893 
894  bool isLess(utils::Value const & other) const
895  {
896  if ( isA<std::string>() && other.isA<std::string>() )
897  {
898  return get<std::string>() < other.get<std::string>();
899  }
900 
901  if (isA<HVersion>() && other.isA<HVersion>())
902  {
903  return get<HVersion>() < other.get<HVersion>();
904  }
905 
906  if (isA<HVersion>() && other.isA<std::string>())
907  {
908  HVersion hver = HVersion::convert(other.get<std::string>().c_str());
909  return get<HVersion>() < hver;
910  }
911 
912  if (isA<std::string>() && other.isA<HVersion>())
913  {
914  HVersion hver = HVersion::convert(get<std::string>().c_str());
915  return hver < other.get<HVersion>();
916  }
917 
918  if (isA<PYVersion>() && other.isA<PYVersion>())
919  {
920  return get<PYVersion>() < other.get<PYVersion>();
921  }
922 
923  if (isA<PYVersion>() && other.isA<std::string>())
924  {
925  PYVersion pyver = PYVersion::convert(other.get<std::string>().c_str());
926  return get<PYVersion>() < pyver;
927  }
928 
929  if (isA<std::string>() && other.isA<PYVersion>())
930  {
931  PYVersion pyver = PYVersion::convert(get<std::string>().c_str());
932  return pyver < other.get<PYVersion>();
933  }
934 
935  if (isA<HPlatformBuildVersion>() && other.isA<HPlatformBuildVersion>())
936  {
937  return get<HPlatformBuildVersion>() < other.get<HPlatformBuildVersion>();
938  }
939 
940  if (isA<HPlatformBuildVersion>() && other.isA<std::string>())
941  {
943  return get<HPlatformBuildVersion>() < pbver;
944  }
945 
946  if (isA<std::string>() && other.isA<HPlatformBuildVersion>())
947  {
948  HPlatformBuildVersion pbver = HPlatformBuildVersion::convert(get<std::string>().c_str());
949  return pbver < other.get<HPlatformBuildVersion>();
950  }
951 
952  if ( isA<std::string>() || other.isA<std::string>() )
953  {
954  throw std::runtime_error("utils::Value::isLess: unsupported types");
955  }
956 
957  return get<fpreal64>() < other.get<fpreal64>();
958  }
959 
960  bool isLessEqual(utils::Value const & other) const
961  {
962  return isLess(other) || isEqual(other);
963  }
964 
965  // Substiture all occurances of find with replace_with
966  bool substitute(char const* find, char const* replace_with)
967  {
968  if (valid() && isA<std::string>())
969  {
970  auto && to_replace = get<std::string>();
971  UT_WorkBuffer wb(to_replace.c_str());
972  if (wb.substitute(find, replace_with))
973  {
974  set(wb.buffer());
975  return true;
976  }
977  }
978  return false;
979  }
980 
981 private:
982  bool compareIgnoreCase(std::string & s1, std::string & s2) const
983  {
984  return ((s1.size() == s2.size()) &&
985  std::equal(s1.begin(), s1.end(), s2.begin(),
986  [](char & c1, char & c2)
987  {
988  return (c1 == c2 || std::toupper(c1) == std::toupper(c2));
989  }
990  ));
991  }
992  hboost::any myValue;
993 }; // Value
994 
995 // Loggger to hold warning/errors/info messages
996 class Logger
997 {
998 public:
1001 
1002  enum class Flags : unsigned
1003  {
1004  all,
1005  info,
1006  warning,
1007  error
1008  };
1009 
1011  : myHasErrorFlag(false)
1012  , myLog(&myDefaultLog)
1013  , myVerboseFlag(false)
1014  {
1015  }
1016 
1017  void setAsVerbose(bool flag)
1018  {
1019  myVerboseFlag = flag;
1020  }
1021 
1022  bool verbose() const
1023  {
1024  return myVerboseFlag;
1025  }
1026 
1027  void error(char const* msg)
1028  {
1029  addToBuffer(klog_error.asHolder(), msg);
1030  if (msg)
1031  {
1032  myHasErrorFlag = true;
1033  }
1034  }
1035 
1036  template< typename ...Args >
1037  void error(char const* msg, Args&&... args)
1038  {
1039  addToBuffer(klog_error.asHolder(), formatMsg(msg, std::forward<Args>(args)...));
1040  if (msg)
1041  {
1042  myHasErrorFlag = true;
1043  }
1044  }
1045 
1046  void info(char const* msg)
1047  {
1048  if (!myVerboseFlag)
1049  {
1050  return;
1051  }
1052  addToBuffer(klog_info.asHolder(), msg);
1053  }
1054 
1055  template< typename ...Args >
1056  void info(char const* msg, Args&&... args)
1057  {
1058  if (!myVerboseFlag)
1059  {
1060  return;
1061  }
1062  addToBuffer(klog_info.asHolder(), formatMsg(msg, std::forward<Args>(args)...));
1063  }
1064 
1065  void message(char const* msg)
1066  {
1067  if (!myVerboseFlag)
1068  {
1069  return;
1070  }
1071  addToBuffer(nullptr, msg);
1072  }
1073 
1074  template< typename ...Args >
1075  void message(char const* msg, Args&&... args)
1076  {
1077  if (!myVerboseFlag)
1078  {
1079  return;
1080  }
1081  addToBuffer(nullptr, formatMsg(msg, std::forward<Args>(args)...));
1082  }
1083 
1084  void warning(char const* msg)
1085  {
1086  addToBuffer(klog_warning.asHolder(), msg);
1087  }
1088 
1089  template< typename ...Args >
1090  void warning(char const* msg, Args&&... args)
1091  {
1092  addToBuffer(klog_warning.asHolder(), formatMsg(msg, std::forward<Args>(args)...));
1093  }
1094 
1095  void clear()
1096  {
1097  myDefaultLog.clear();
1098  myEntryMap.clear();
1099  myEntryArray.clear();
1100  myErrorArray.clear();
1101  myWarningArray.clear();
1102  myHasErrorFlag = false;
1103  }
1104 
1106  {
1107  myErrorArray.clear();
1108  myHasErrorFlag = false;
1109  }
1110 
1111  void toStream(std::ostream &os) const
1112  {
1113  for (auto && entry : myEntryArray)
1114  {
1115  os << entry.c_str() << std::endl;
1116  auto && it = myEntryMap.find(entry);
1117  os << it->second.c_str() << std::endl;
1118  }
1119 
1120  if (myDefaultLog)
1121  {
1122  os << myDefaultLog.c_str() << std::endl;
1123  }
1124  }
1125 
1126  UT_StringHolder toString(bool header=true) const
1127  {
1128  UT_OStringStream ss;
1129  toStream(ss);
1131  if (header && myVerboseFlag)
1132  {
1133  log += "= = = Houdini Package log = = =\n";
1134  }
1135 
1136  log += ss.str().buffer();
1137 
1138  if (header && myVerboseFlag)
1139  {
1140  log += "= = = = = = = = = = = = = = = =\n";
1141  }
1142  return log;
1143  }
1144 
1145  UT_StringArray const & errors() const
1146  {
1147  return myErrorArray;
1148  }
1149 
1150  UT_StringArray const & warnings() const
1151  {
1152  return myWarningArray;
1153  }
1154 
1155  void log(char const* title, Flags flags=Flags::all) const
1156  {
1157  if (flags == Flags::all)
1158  {
1159  std::cout << title << std::endl;
1160  toStream(std::cout);
1161  }
1162  else if (myHasErrorFlag && flags == Flags::error)
1163  {
1164  std::cerr << title << std::endl;
1165  toStream(std::cerr);
1166  }
1167  }
1168 
1169  void start(char const * entry)
1170  {
1171  if (!entry)
1172  {
1173  // global logging
1174  myLog = &myDefaultLog;
1175  return;
1176  }
1177 
1178  // logging done per entry
1179  if (!myEntryMap.count(entry))
1180  {
1181  myEntryMap[entry] = UT_StringHolder();
1182  myEntryArray.append(entry);
1183  }
1184  myLog = &myEntryMap[entry];
1185  }
1186 
1187  bool hasErrors() const
1188  {
1189  return myHasErrorFlag;
1190  }
1191 
1192  void append(Logger const & logger)
1193  {
1194  UT_OStringStream ss;
1195  logger.toStream(ss);
1196 
1197  UT_WorkBuffer wb;
1198  wb += ss.str().buffer();
1199 
1200  if (wb.buffer())
1201  {
1202  buffer() += wb.buffer();
1203  }
1204  }
1205 
1206 private:
1207  template< typename ...Args >
1208  UT_StringHolder formatMsg( const char* format, Args &&... args )
1209  {
1210  UT_WorkBuffer wb;
1211  wb.format(format, args...);
1212  return wb;
1213  }
1214 
1215  void addToBuffer(const char* prefix, const char* msg)
1216  {
1217  if (!msg || !strlen(msg))
1218  {
1219  return;
1220  }
1221 
1222  if (prefix)
1223  {
1224  buffer() += prefix;
1225  buffer() += ": ";
1226  }
1227  buffer() += msg;
1228  buffer() += "\n";
1229 
1230  if ( msg && prefix && klog_error.asHolder().equal(prefix))
1231  {
1232  myErrorArray.append(msg);
1233  }
1234  else if ( msg && prefix && klog_warning.asHolder().equal(prefix))
1235  {
1236  myWarningArray.append(msg);
1237  }
1238  }
1239 
1240  UT_StringHolder & buffer()
1241  {
1242  return *myLog;
1243  }
1244 
1245  UT_StringHolder const & buffer() const
1246  {
1247  return *myLog;
1248  }
1249 
1250  EntryArray myEntryArray;
1251  EntryMap myEntryMap;
1252  UT_StringHolder* myLog;
1253  UT_StringHolder myDefaultLog;
1254  UT_StringArray myWarningArray;
1255  UT_StringArray myErrorArray;
1256  bool myHasErrorFlag;
1257  bool myVerboseFlag;
1258 }; // Logger
1259 
1260 } // utils
1261 } // UT_Package
1262 
1263 #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:832
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:1088
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
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:716
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