sassc 1.11.1 → 1.11.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -2
  3. data/README.md +3 -2
  4. data/ext/libsass/Makefile.conf +2 -1
  5. data/ext/libsass/appveyor.yml +10 -5
  6. data/ext/libsass/docs/dev-ast-memory.md +223 -0
  7. data/ext/libsass/include/sass/base.h +2 -0
  8. data/ext/libsass/script/bootstrap +7 -4
  9. data/ext/libsass/script/ci-build-libsass +3 -3
  10. data/ext/libsass/script/ci-install-compiler +2 -0
  11. data/ext/libsass/script/ci-report-coverage +2 -1
  12. data/ext/libsass/script/test-leaks.pl +103 -0
  13. data/ext/libsass/src/ast.cpp +621 -495
  14. data/ext/libsass/src/ast.hpp +801 -367
  15. data/ext/libsass/src/ast_def_macros.hpp +5 -5
  16. data/ext/libsass/src/ast_fwd_decl.hpp +312 -14
  17. data/ext/libsass/src/bind.cpp +54 -51
  18. data/ext/libsass/src/bind.hpp +3 -7
  19. data/ext/libsass/src/check_nesting.cpp +117 -120
  20. data/ext/libsass/src/check_nesting.hpp +38 -34
  21. data/ext/libsass/src/color_maps.cpp +3 -3
  22. data/ext/libsass/src/color_maps.hpp +3 -3
  23. data/ext/libsass/src/context.cpp +33 -34
  24. data/ext/libsass/src/context.hpp +12 -14
  25. data/ext/libsass/src/cssize.cpp +200 -228
  26. data/ext/libsass/src/cssize.hpp +49 -49
  27. data/ext/libsass/src/debugger.hpp +260 -241
  28. data/ext/libsass/src/emitter.cpp +6 -6
  29. data/ext/libsass/src/emitter.hpp +7 -7
  30. data/ext/libsass/src/environment.cpp +2 -2
  31. data/ext/libsass/src/environment.hpp +0 -2
  32. data/ext/libsass/src/error_handling.cpp +5 -5
  33. data/ext/libsass/src/error_handling.hpp +12 -12
  34. data/ext/libsass/src/eval.cpp +412 -401
  35. data/ext/libsass/src/eval.hpp +61 -62
  36. data/ext/libsass/src/expand.cpp +223 -204
  37. data/ext/libsass/src/expand.hpp +42 -42
  38. data/ext/libsass/src/extend.cpp +198 -201
  39. data/ext/libsass/src/extend.hpp +12 -14
  40. data/ext/libsass/src/file.hpp +4 -5
  41. data/ext/libsass/src/functions.cpp +413 -418
  42. data/ext/libsass/src/functions.hpp +7 -10
  43. data/ext/libsass/src/inspect.cpp +115 -109
  44. data/ext/libsass/src/inspect.hpp +69 -69
  45. data/ext/libsass/src/listize.cpp +31 -33
  46. data/ext/libsass/src/listize.hpp +8 -10
  47. data/ext/libsass/src/memory/SharedPtr.cpp +116 -0
  48. data/ext/libsass/src/memory/SharedPtr.hpp +202 -0
  49. data/ext/libsass/src/node.cpp +45 -43
  50. data/ext/libsass/src/node.hpp +15 -15
  51. data/ext/libsass/src/operation.hpp +136 -136
  52. data/ext/libsass/src/output.cpp +48 -49
  53. data/ext/libsass/src/output.hpp +14 -14
  54. data/ext/libsass/src/parser.cpp +530 -554
  55. data/ext/libsass/src/parser.hpp +91 -96
  56. data/ext/libsass/src/prelexer.cpp +13 -10
  57. data/ext/libsass/src/remove_placeholders.cpp +25 -21
  58. data/ext/libsass/src/remove_placeholders.hpp +7 -7
  59. data/ext/libsass/src/sass2scss.cpp +2 -1
  60. data/ext/libsass/src/sass_context.cpp +125 -107
  61. data/ext/libsass/src/sass_context.hpp +1 -1
  62. data/ext/libsass/src/sass_util.hpp +5 -5
  63. data/ext/libsass/src/sass_values.cpp +27 -27
  64. data/ext/libsass/src/source_map.cpp +2 -2
  65. data/ext/libsass/src/source_map.hpp +2 -2
  66. data/ext/libsass/src/subset_map.cpp +57 -0
  67. data/ext/libsass/src/subset_map.hpp +8 -76
  68. data/ext/libsass/src/to_c.cpp +13 -13
  69. data/ext/libsass/src/to_c.hpp +14 -14
  70. data/ext/libsass/src/to_value.cpp +20 -20
  71. data/ext/libsass/src/to_value.hpp +20 -21
  72. data/ext/libsass/src/util.cpp +55 -88
  73. data/ext/libsass/src/util.hpp +9 -13
  74. data/ext/libsass/src/values.cpp +27 -26
  75. data/ext/libsass/src/values.hpp +2 -2
  76. data/ext/libsass/test/test_subset_map.cpp +69 -69
  77. data/ext/libsass/win/libsass.targets +3 -2
  78. data/ext/libsass/win/libsass.vcxproj.filters +9 -6
  79. data/lib/sassc/version.rb +1 -1
  80. data/sassc.gemspec +0 -1
  81. data/test/native_test.rb +1 -1
  82. metadata +7 -5
  83. data/ext/libsass/src/ast_factory.hpp +0 -92
  84. data/ext/libsass/src/memory_manager.cpp +0 -77
  85. data/ext/libsass/src/memory_manager.hpp +0 -48
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2003bd0fdc35ac8281c0f203771b9e88e3554ce6
4
- data.tar.gz: 4181ece117d80e29ff8abf55805fc8e7710e3c3f
3
+ metadata.gz: 4b738b9d16e9e4b192dd5648204b01388b12d1e2
4
+ data.tar.gz: 83c05efa8d19833ef97ca727bba32441de3ea154
5
5
  SHA512:
6
- metadata.gz: 44ff8a7c1c903405f2124f670b5277fee9f47bd4f61c5c429524b1812a8c3497fd1f4c0ca6812bc886b4414bdeb70846f3a69aef2d0cfd124c5cc30c2e332773
7
- data.tar.gz: cc5690cb269eaa0408ae7c5b6f72aa71b11530357a72b930f3bfcae95ef56df708b97ba1a0c7af6e806802479023e4a306e22ae3758fac656bec84dbb270b494
6
+ metadata.gz: f6a44d53f4bd75fd8c9ad74051d89d41bbd9b8920715895ec501c3ee1ce5cf7b54bb056623d59b7e52e2c49ad59a27be3486e0d2c087453a4cafb5b16d19e4b4
7
+ data.tar.gz: 9afe2183443c33e38313d41d43d8072b39bb78057bdd47e75455288311b140604d819e1d7900b301a2712f4752f1944fbc29d226732a3a6458458765ced549d9
@@ -3,8 +3,8 @@ language: ruby
3
3
  bundler_args: "--binstubs --standalone --without documentation --path ../bundle"
4
4
  script: "bundle exec rake test"
5
5
  rvm:
6
- - 2.0.0
7
- - 2.1.5
8
6
  - 2.2.0
7
+ - 2.3.3
8
+ - 2.4.0
9
9
  notifications:
10
10
  email: false
data/README.md CHANGED
@@ -6,7 +6,7 @@ This gem combines the speed of `libsass`, the [Sass C implementation](https://gi
6
6
 
7
7
  ### libsass Version
8
8
 
9
- [3.4.1](https://github.com/sass/libsass/releases/tag/3.4.1)
9
+ [3.4.3](https://github.com/sass/libsass/releases/tag/3.4.3)
10
10
 
11
11
  ## Installation
12
12
 
@@ -48,7 +48,8 @@ This gem is maintained by [Ryan Boland](https://ryanboland.com)
48
48
  and [awesome contributors](https://github.com/bolandrm/sassc-ruby/graphs/contributors).
49
49
 
50
50
  ## Changelog
51
-
51
+ - **1.11.2**
52
+ - [Update to libsass 3.4.3](https://github.com/sass/sassc-ruby/pull/65)
52
53
  - **1.11.1**
53
54
  - [Update to libsass 3.4.1](https://github.com/sass/sassc-ruby/pull/61)
54
55
  - **1.11.0**
@@ -43,8 +43,9 @@ SOURCES = \
43
43
  to_c.cpp \
44
44
  to_value.cpp \
45
45
  source_map.cpp \
46
+ subset_map.cpp \
46
47
  error_handling.cpp \
47
- memory_manager.cpp \
48
+ memory/SharedPtr.cpp \
48
49
  utf8_string.cpp \
49
50
  base64vlq.cpp
50
51
 
@@ -3,7 +3,7 @@ os: Visual Studio 2013
3
3
  environment:
4
4
  CTEST_OUTPUT_ON_FAILURE: 1
5
5
  ruby_version: 22-x64
6
- TargetPath: sassc/bin/sassc
6
+ TargetPath: sassc/bin/sassc.exe
7
7
  matrix:
8
8
  - Compiler: msvc
9
9
  Config: Release
@@ -63,14 +63,19 @@ test_script:
63
63
  git -C sass-spec checkout -q --force ci-spec-pr-$SPEC_PR
64
64
  }
65
65
  }
66
- ruby sass-spec/sass-spec.rb -V 3.4 --probe-todo --impl libsass -c $env:TargetPath -s sass-spec/spec
67
- if(-not($?)) {
68
- echo "sass-spec tests failed"
66
+ $env:TargetPath = Join-Path $pwd.Path $env:TargetPath
67
+ If (Test-Path "$env:TargetPath") {
68
+ ruby sass-spec/sass-spec.rb -V 3.4 --probe-todo --impl libsass -c $env:TargetPath -s sass-spec/spec
69
+ if(-not($?)) {
70
+ echo "sass-spec tests failed"
71
+ exit 1
72
+ }
73
+ } else {
74
+ echo "spec runner not found (compile error?)"
69
75
  exit 1
70
76
  }
71
77
  Write-Host "Explicitly testing the case when cwd has Cyrillic characters: " -nonewline
72
78
  # See comments in gh-1774 for details.
73
- $env:TargetPath = Join-Path $pwd.Path $env:TargetPath
74
79
  cd sass-spec/spec/libsass/Sáss-UŢF8/
75
80
  &$env:TargetPath ./input.scss 2>&1>$null
76
81
  if(-not($?)) {
@@ -0,0 +1,223 @@
1
+ # LibSass smart pointer implementation
2
+
3
+ LibSass uses smart pointers very similar to `shared_ptr` known
4
+ by Boost or C++11. Implementation is a bit less modular since
5
+ it was not needed. Various compile time debug options are
6
+ available if you need to debug memory life-cycles.
7
+
8
+
9
+ ## Memory Classes
10
+
11
+ ### SharedObj
12
+
13
+ Base class for the actual node implementations. This ensures
14
+ that every object has a reference counter and other values.
15
+
16
+ ```c++
17
+ class AST_Node : public SharedObj { ... };
18
+ ```
19
+
20
+ ### SharedPtr (base class for SharedImpl)
21
+
22
+ Base class that holds on to the pointer. The reference counter
23
+ is stored inside the pointer object directly (`SharedObj`).
24
+
25
+ ### SharedImpl (inherits from SharedPtr)
26
+
27
+ This is the main base class for objects you use in your code. It
28
+ will make sure that the memory it points at will be deleted once
29
+ all copies to the same object/memory go out of scope.
30
+
31
+ ```c++
32
+ Class* pointer = new Class(...);
33
+ SharedImpl<Class> obj(pointer);
34
+ ```
35
+
36
+ To spare the developer of typing the templated class every time,
37
+ we created typedefs for each available AST Node specialization.
38
+
39
+ ```c++
40
+ typedef SharedImpl<Number> Number_Obj;
41
+ Number_Obj number = SASS_MEMORY_NEW(...);
42
+ ```
43
+
44
+
45
+ ## Memory life-cycles
46
+
47
+ ### Pointer pickups
48
+
49
+ I often use the terminology of "pickup". This means the moment when
50
+ a raw pointer not under any control is assigned to a reference counted
51
+ object (`XYZ_Obj = XYZ_Ptr`). From that point on memory will be
52
+ automatically released once the object goes out of scope (but only
53
+ if the reference counter reaches zero). Main point beeing, you don't
54
+ have to worry about memory management yourself.
55
+
56
+ ### Object detach
57
+
58
+ Sometimes we can't return reference counted objects directly (see
59
+ invalid covariant return types problems below). But we often still
60
+ need to use reference objects inside a function to avoid leaks when
61
+ something throws. For this you can use `detach`, which basically
62
+ detaches the pointer memory from the reference counted object. So
63
+ when the reference counted object goes out of scope, it will not
64
+ free the attached memory. You are now again in charge of freeing
65
+ the memory (just assign it to a reference counted object again).
66
+
67
+
68
+ ## Circular references
69
+
70
+ Reference counted memory implementations are prone to circular references.
71
+ This can be addressed by using a multi generation garbage collector. But
72
+ for our use-case that seems overkill. There is no way so far for users
73
+ (sass code) to create circular references. Therefore we can code around
74
+ this possible issue. But developers should be aware of this limitation.
75
+
76
+ There are AFAIR two places where circular references could happen. One is
77
+ the `sources` member on every `Selector`. The other one can happen in the
78
+ extend code (Node handling). The easy way to avoid this is to only assign
79
+ complete object clones to these members. If you know the objects lifetime
80
+ is longer than the reference you create, you can also just store the raw
81
+ pointer. Once needed this could be solved with weak pointers.
82
+
83
+
84
+ ## Addressing the invalid covariant return types problems
85
+
86
+ If you are not familiar with the mentioned problem, you may want
87
+ to read up on covariant return types and virtual functions, i.e.
88
+
89
+ - http://stackoverflow.com/questions/6924754/return-type-covariance-with-smart-pointers
90
+ - http://stackoverflow.com/questions/196733/how-can-i-use-covariant-return-types-with-smart-pointers
91
+ - http://stackoverflow.com/questions/2687790/how-to-accomplish-covariant-return-types-when-returning-a-shared-ptr
92
+
93
+ We hit this issue at least with the CRTP visitor pattern (eval, expand,
94
+ listize and so forth). This means we cannot return reference counted
95
+ objects directly. We are forced to return raw pointers or we would need
96
+ to have a lot of explicit and expensive upcasts by callers/consumers.
97
+
98
+ ### Simple functions that allocate new AST Nodes
99
+
100
+ In the parser step we often create new objects and can just return a
101
+ unique pointer (meaning ownership clearly shifts back to the caller).
102
+ The caller/consumer is responsible that the memory is freed.
103
+
104
+ ```c++
105
+ typedef Number* Number_Ptr;
106
+ int parse_integer() {
107
+ ... // do the parsing
108
+ return 42;
109
+ }
110
+ Number_Ptr parse_number() {
111
+ Number_Ptr p_nr = SASS_MEMORY_NEW(...);
112
+ p_nr->value(parse_integer());
113
+ return p_nr;
114
+ }
115
+ Number_Obj nr = parse_number();
116
+ ```
117
+
118
+ The above would be the encouraged pattern for such simple cases.
119
+
120
+ ### Allocate new AST Nodes in functions that can throw
121
+
122
+ There is a major caveat with the previous example, considering this
123
+ more real-life implementation that throws an error. The throw may
124
+ happen deep down in another function. Holding raw pointers that
125
+ we need to free would leak in this case.
126
+
127
+ ```c++
128
+ int parse_integer() {
129
+ ... // do the parsing
130
+ if (error) throw(error);
131
+ return 42;
132
+ }
133
+ ```
134
+
135
+ With this `parse_integer` function the previous example would leak memory.
136
+ I guess it is pretty obvious, as the allocated memory will not be freed,
137
+ as it was never assigned to a SharedObj value. Therefore the above code
138
+ would better be written as:
139
+
140
+ ```c++
141
+ typedef Number* Number_Ptr;
142
+ int parse_integer() {
143
+ ... // do the parsing
144
+ if (error) throw(error);
145
+ return 42;
146
+ }
147
+ // this leaks due to pointer return
148
+ // should return Number_Obj instead
149
+ // though not possible for virtuals!
150
+ Number_Ptr parse_number() {
151
+ Number_Obj nr = SASS_MEMORY_NEW(...);
152
+ nr->value(parse_integer()); // throws
153
+ return &nr; // Ptr from Obj
154
+ }
155
+ Number_Obj nr = parse_number();
156
+ // will now be freed automatically
157
+ ```
158
+
159
+ The example above unfortunately will not work as is, since we return a
160
+ `Number_Ptr` from that function. Therefore the object allocated inside
161
+ the function is already gone when it is picked up again by the caller.
162
+ The easy fix for the given simplified use case would be to change the
163
+ return type of `parse_number` to `Number_Obj`. Indeed we do it exactly
164
+ this way in the parser. But as stated above, this will not work for
165
+ virtual functions due to invalid covariant return types!
166
+
167
+ ### Return managed objects from virtual functions
168
+
169
+ The easy fix would be to just create a new copy on the heap and return
170
+ that. But this seems like a very inelegant solution to this problem. I
171
+ mean why can't we just tell the object to treat it like a newly allocated
172
+ object? And indeed we can. I've added a `detach` method that will tell
173
+ the object to survive deallocation until the next pickup. This means
174
+ that it will leak if it is not picked up by consumer.
175
+
176
+ ```c++
177
+ typedef Number* Number_Ptr;
178
+ int parse_integer() {
179
+ ... // do the parsing
180
+ if (error) throw(error);
181
+ return 42;
182
+ }
183
+ Number_Ptr parse_number() {
184
+ Number_Obj nr = SASS_MEMORY_NEW(...);
185
+ nr->value(parse_integer()); // throws
186
+ return nr.detach();
187
+ }
188
+ Number_Obj nr = parse_number();
189
+ // will now be freed automatically
190
+ ```
191
+
192
+
193
+ ## Compile time debug options
194
+
195
+ To enable memory debugging you need to define `DEBUG_SHARED_PTR`.
196
+ This can i.e. be done in `include/sass/base.h`
197
+
198
+ ```c++
199
+ define DEBUG_SHARED_PTR
200
+ ```
201
+
202
+ This will print lost memory on exit to stderr. You can also use
203
+ `setDbg(true)` on sepecific variables to emit reference counter
204
+ increase, decrease and other events.
205
+
206
+
207
+ ## Why reinvent the wheel when there is `shared_ptr` from C++11
208
+
209
+ First, implementing a smart pointer class is not really that hard. It
210
+ was indeed also a learning experience for myself. But there are more
211
+ profound advantages:
212
+
213
+ - Better GCC 4.4 compatibility (which most code still has OOTB)
214
+ - Not thread safe (give us some free performance on some compiler)
215
+ - Beeing able to track memory allocations for debugging purposes
216
+ - Adding additional features if needed (as seen in `detach`)
217
+ - Optional: optimized weak pointer implementation possible
218
+
219
+ ### Thread Safety
220
+
221
+ As said above, this is not thread safe currently. But we don't need
222
+ this ATM anyway. And I guess we probably never will share AST Nodes
223
+ across different threads.
@@ -1,6 +1,8 @@
1
1
  #ifndef SASS_BASE_H
2
2
  #define SASS_BASE_H
3
3
 
4
+ // #define DEBUG_SHARED_PTR
5
+
4
6
  #ifdef _MSC_VER
5
7
  #pragma warning(disable : 4503)
6
8
  #ifndef _SCL_SECURE_NO_WARNINGS
@@ -2,9 +2,12 @@
2
2
 
3
3
  script/branding
4
4
 
5
- if [ ! -d "sass-spec" ]; then
6
- git clone https://github.com/sass/sass-spec.git
5
+ : ${SASS_SPEC_PATH:="sass-spec"}
6
+ : ${SASS_SASSC_PATH:="sassc" }
7
+
8
+ if [ ! -d $SASS_SPEC_PATH ]; then
9
+ git clone https://github.com/sass/sass-spec.git $SASS_SPEC_PATH
7
10
  fi
8
- if [ ! -d "sassc" ]; then
9
- git clone https://github.com/sass/sassc.git
11
+ if [ ! -d $SASS_SASSC_PATH ]; then
12
+ git clone https://github.com/sass/sassc.git $SASS_SASSC_PATH
10
13
  fi
@@ -120,10 +120,10 @@ then
120
120
  echo "Fetching Sass Spec PR $SPEC_PR"
121
121
  git -C sass-spec fetch -u origin pull/$SPEC_PR/head:ci-spec-pr-$SPEC_PR
122
122
  git -C sass-spec checkout --force ci-spec-pr-$SPEC_PR
123
- LD_LIBRARY_PATH="$PREFIX/lib/" make $MAKE_OPTS test_build
123
+ LD_LIBRARY_PATH="$PREFIX/lib/" make $MAKE_OPTS test_probe
124
124
  else
125
- LD_LIBRARY_PATH="$PREFIX/lib/" make $MAKE_OPTS test_build
125
+ LD_LIBRARY_PATH="$PREFIX/lib/" make $MAKE_OPTS test_probe
126
126
  fi
127
127
  else
128
- LD_LIBRARY_PATH="$PREFIX/lib/" make $MAKE_OPTS test_build
128
+ LD_LIBRARY_PATH="$PREFIX/lib/" make $MAKE_OPTS test_probe
129
129
  fi
@@ -2,3 +2,5 @@
2
2
 
3
3
  gem install minitest
4
4
  gem install minitap
5
+
6
+ pip install --user 'requests[security]'
@@ -3,7 +3,8 @@
3
3
  if [ "x$COVERAGE" = "xyes" ]; then
4
4
 
5
5
  # exclude some directories from profiling (.libs is from autotools)
6
- export EXCLUDE_COVERAGE="--exclude src/sassc
6
+ export EXCLUDE_COVERAGE="--exclude plugins
7
+ --exclude sassc/sassc.c
7
8
  --exclude src/sass-spec
8
9
  --exclude src/.libs
9
10
  --exclude src/debug.hpp
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/perl
2
+ ############################################################
3
+ # this perl script is meant for developers only!
4
+ # it will run all spec-tests (without verifying the
5
+ # results) via valgrind to detect possible leaks.
6
+ # expect that it takes 1h or more to finish!
7
+ ############################################################
8
+ # Prerequisite install: `cpan Parallel::Runner`
9
+ # You may also need to install `cpan File::Find`
10
+ # You may also need to install `cpan IPC::Run3`
11
+ ############################################################
12
+ # usage: `perl test-leaks.pl [threads]`
13
+ # example: `time perl test-leaks.pl 4`
14
+ ############################################################
15
+ # leaks will be reported in "mem-leaks.log"
16
+ ############################################################
17
+
18
+ use strict;
19
+ use warnings;
20
+
21
+ ############################################################
22
+ # configurations (you may adjust)
23
+ ############################################################
24
+
25
+ # number of threads to use
26
+ my $threads = $ARGV[0] || 8;
27
+
28
+ # the github repositories to checkout
29
+ # if you need other branch, clone manually!
30
+ my $sassc = "https://www.github.com/sass/sassc";
31
+ my $specs = "https://www.github.com/sass/sass-spec";
32
+
33
+ ############################################################
34
+ # load modules
35
+ ############################################################
36
+
37
+ use IPC::Run3;
38
+ use IO::Handle;
39
+ use Fcntl qw(:flock);
40
+ use File::Find::Rule;
41
+ use Parallel::Runner;
42
+ use List::Util qw(shuffle);
43
+
44
+ ############################################################
45
+ # check prerequisites
46
+ ############################################################
47
+
48
+ unless (-d "../sassc") {
49
+ warn "sassc folder not found\n";
50
+ warn "trying to checkout via git\n";
51
+ system("git", "clone", $sassc, "../sassc");
52
+ die "git command did not exit gracefully" if $?;
53
+ }
54
+
55
+ unless (-d "../sass-spec") {
56
+ warn "sass-spec folder not found\n";
57
+ warn "trying to checkout via git\n";
58
+ system("git", "clone", $specs, "../sass-spec");
59
+ die "git command did not exit gracefully" if $?;
60
+ }
61
+
62
+ unless (-f "../sassc/bin/sassc") {
63
+ warn "sassc executable not found\n";
64
+ warn "trying to compile via make\n";
65
+ system("make", "-C", "../sassc", "-j", $threads);
66
+ die "make command did not exit gracefully" if $?;
67
+ }
68
+
69
+ ############################################################
70
+ # main runner code
71
+ ############################################################
72
+
73
+ my $root = "../sass-spec/spec";
74
+ my @files = File::Find::Rule->file()
75
+ ->name('input.scss')->in($root);
76
+
77
+ open(my $leaks, ">", "mem-leaks.log");
78
+ die "Cannot open log" unless $leaks;
79
+ my $runner = Parallel::Runner->new($threads);
80
+ die "Cannot start runner" unless $runner;
81
+
82
+ print "##########################\n";
83
+ print "Testing $#files spec files\n";
84
+ print "##########################\n";
85
+
86
+ foreach my $file (shuffle @files) {
87
+ $runner->run(sub {
88
+ $| = 1; select STDOUT;
89
+ my $cmd = sprintf('../sassc/bin/sassc %s', $file);
90
+ my $check = sprintf('valgrind --leak-check=yes %s', $cmd);
91
+ run3($check, undef, \ my $out, \ my $err);
92
+ if ($err =~ m/in use at exit: 0 bytes in 0 blocks/) {
93
+ print "."; # print success indicator
94
+ } else {
95
+ print "F"; # print error indicator
96
+ flock($leaks, LOCK_EX) or die "Cannot lock log";
97
+ $leaks->printflush("#" x 80, "\n", $err, "\n");
98
+ flock($leaks, LOCK_UN) or die "Cannot unlock log";
99
+ }
100
+ });
101
+ }
102
+
103
+ $runner->finish;