• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / smartsprites / #43

11 Nov 2023 07:47PM UTC coverage: 88.431%. Remained the same
#43

push

github

hazendaz
[tests] Fix tests given they expected order and now license on everything for +36

1437 of 1625 relevant lines covered (88.43%)

0.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.24
/src/main/java/org/carrot2/labs/smartsprites/SmartSpritesParameters.java
1
/*
2
 * SmartSprites Project
3
 *
4
 * Copyright (C) 2007-2009, Stanisław Osiński.
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without modification,
8
 * are permitted provided that the following conditions are met:
9
 *
10
 * - Redistributions of  source code must  retain the above  copyright notice, this
11
 *   list of conditions and the following disclaimer.
12
 *
13
 * - Redistributions in binary form must reproduce the above copyright notice, this
14
 *   list of conditions and the following  disclaimer in  the documentation  and/or
15
 *   other materials provided with the distribution.
16
 *
17
 * - Neither the name of the SmartSprites Project nor the names of its contributors
18
 *   may  be used  to endorse  or  promote  products derived   from  this  software
19
 *   without specific prior written permission.
20
 *
21
 * - We kindly request that you include in the end-user documentation provided with
22
 *   the redistribution and/or in the software itself an acknowledgement equivalent
23
 *   to  the  following: "This product includes software developed by the SmartSprites
24
 *   Project."
25
 *
26
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"  AND
27
 * ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED  TO, THE IMPLIED
28
 * WARRANTIES  OF  MERCHANTABILITY  AND  FITNESS  FOR  A  PARTICULAR  PURPOSE   ARE
29
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE  FOR
30
 * ANY DIRECT, INDIRECT, INCIDENTAL,  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  DAMAGES
31
 * (INCLUDING, BUT  NOT LIMITED  TO, PROCUREMENT  OF SUBSTITUTE  GOODS OR SERVICES;
32
 * LOSS OF USE, DATA, OR PROFITS;  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND  ON
33
 * ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT  LIABILITY,  OR TORT
34
 * (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY WAY  OUT OF THE USE  OF THIS
35
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
 */
37
package org.carrot2.labs.smartsprites;
38

39
import java.io.File;
40
import java.io.IOException;
41
import java.nio.charset.StandardCharsets;
42
import java.util.List;
43

44
import org.carrot2.labs.smartsprites.message.MessageLog;
45
import org.carrot2.labs.smartsprites.message.Message.MessageLevel;
46
import org.carrot2.labs.smartsprites.message.Message.MessageType;
47
import org.carrot2.util.FileUtils;
48
import org.carrot2.util.StringUtils;
49
import org.kohsuke.args4j.Argument;
50
import org.kohsuke.args4j.Option;
51

52
/**
53
 * Contains invocation parameters for SmartSprites, provides methods for validating the
54
 * parameters.
55
 */
56
public final class SmartSpritesParameters
57
{
58
    /**
59
     * Path to the directory that contains the css files to be processed. Directories
60
     * containing CSS and image files must be writable, unless output.dir.path is
61
     * provided. The root.dir.path can be either absolute, e.g. c:/myproject/web or
62
     * relative to the directory in which this script is run.
63
     */
64
    @Option(name = "--root-dir-path", required = false, metaVar = "DIR")
65
    private String rootDir;
66

67
    /**
68
     * Paths to individual CSS files to process. Either {@link #rootDir} or
69
     * {@link #cssFiles} must be not empty. If only {@link #cssFiles} is not empty,
70
     * {@link #outputDir} must be blank. If both {@link #rootDir} and {@link #cssFiles}
71
     * are not empty, {@link #outputDir} is supported but only {@link #cssFiles} from
72
     * {@link #rootDir} are processed.
73
     */
74
    @Argument(metaVar = "CSS-FILES")
75
    @Option(name = "--css-files", required = false, metaVar = "FILES")
76
    private List<String> cssFiles;
77

78
    /**
79
     * Output directory for processed CSS files and CSS-relative sprite images. The
80
     * directory structure relative to root.dir.path will be preserved in the output
81
     * directory. E.g. if CSS files are contained in the css/base directory of
82
     * root.dir.path, the processed results will be written to output.dir.path/css/base.
83
     * Also, CSS-relative sprite images will be written to the output directory. Sprite
84
     * images with document-root-relative URLs will be written relative to the
85
     * document.root.dir.path.
86
     * <p>
87
     * If the output.dir.path directory does not exist, it will be created.
88
     * <p>
89
     * You can leave this property empty, in which case the CSS files will be written next
90
     * to the original CSS files with css.file.suffix, and sprite images will be written
91
     * relative to CSS files.
92
     * <p>
93
     * If you are using a non-empty output.dir.path, you might want to use an empty
94
     * css.file.suffix.
95
     */
96
    @Option(name = "--output-dir-path", metaVar = "DIR")
97
    private String outputDir;
98

99
    /**
100
     * Document root path for document-root-relative (starting with '/') image urls in
101
     * CSS. All such image URLs will be taken relative to document.root.dir.path. Also
102
     * document-root-relative sprite URLs will be written relative to
103
     * document.root.dir.path. You can leave this property empty if your CSS uses only
104
     * CSS-relative image URLs. *
105
     */
106
    @Option(name = "--document-root-dir-path", metaVar = "DIR")
107
    private String documentRootDir;
108

109
    /**
110
     * Message logging level. If you're getting lots of INFO messages and want to see only
111
     * warnings, set this option to WARN.
112
     */
113
    @Option(name = "--log-level")
114
    private MessageLevel logLevel;
115

116
    /**
117
     * The encoding to assume for input and output CSS files.
118
     */
119
    @Option(name = "--css-file-encoding")
120
    private String cssFileEncoding;
121

122
    /**
123
     * Suffix to be appended to the processed CSS file name.
124
     */
125
    @Option(name = "--css-file-suffix")
126
    private String cssFileSuffix;
127

128
    /**
129
     * The required depth of the generated PNG sprites.
130
     */
131
    @Option(name = "--sprite-png-depth")
132
    private PngDepth spritePngDepth;
133

134
    /**
135
     * If <code>true</code>, SmartSprites will generate IE6-friendly PNG sprites if
136
     * needed.
137
     */
138
    @Option(name = "--sprite-png-ie6")
139
    private boolean spritePngIe6;
140

141
    /**
142
     * If <code>true</code>, SmartSprites will generate the sprite directive indicating
143
     * that the image is a sprite image.
144
     */
145
    @Option(name = "--mark-sprite-images")
146
    private boolean markSpriteImages;
147

148
    /** The default suffix to be added to the generated CSS files. */
149
    public static final String DEFAULT_CSS_FILE_SUFFIX = "-sprite";
150

151
    /** By default, we use full color only when necessary */
152
    public static final PngDepth DEFAULT_SPRITE_PNG_DEPTH = PngDepth.AUTO;
1✔
153

154
    /** By default, we don't generate separate sprites for IE6 */
155
    public static final boolean DEFAULT_SPRITE_PNG_IE6 = false;
156

157
    /** By default, we'll assume CSS files are UTF-8 encoded */
158
    public static final String DEFAULT_CSS_FILE_ENCODING = StandardCharsets.UTF_8.name();
1✔
159

160
    /** The default logging level. */
161
    public static final MessageLevel DEFAULT_LOGGING_LEVEL = MessageLevel.INFO;
1✔
162

163
    /** By default, we don't generate sprite directive in output css */
164
    public static final boolean DEFAULT_MARK_SPRITE_IMAGES = false;
165

166
    public enum PngDepth
1✔
167
    {
168
        AUTO, INDEXED, DIRECT;
1✔
169
    }
170

171
    /**
172
     * Creates the parameters with default options and null root dir, before root dir is
173
     * set, the parameters are invalid.
174
     */
175
    public SmartSpritesParameters()
176
    {
177
        this(null);
×
178
    }
×
179

180
    /**
181
     * Creates the parameters with most default values.
182
     */
183
    public SmartSpritesParameters(String rootDir)
184
    {
185
        this(rootDir, null, null, null, MessageLevel.INFO, DEFAULT_CSS_FILE_SUFFIX,
×
186
            DEFAULT_SPRITE_PNG_DEPTH, DEFAULT_SPRITE_PNG_IE6, DEFAULT_CSS_FILE_ENCODING,
187
            DEFAULT_MARK_SPRITE_IMAGES);
188
    }
×
189

190
    /**
191
     * Creates the parameters.
192
     */
193
    public SmartSpritesParameters(String rootDir, List<String> cssFiles,
194
        String outputDir, String documentRootDir, MessageLevel logLevel,
195
        String cssFileSuffix, PngDepth spritePngDepth, boolean spritePngIe6,
196
        String cssEncoding)
197
    {
198
        this(rootDir, cssFiles, outputDir, documentRootDir, logLevel, cssFileSuffix,
1✔
199
            spritePngDepth, spritePngIe6, cssEncoding, DEFAULT_MARK_SPRITE_IMAGES);
200
    }
1✔
201

202
    /**
203
     * Creates the parameters.
204
     */
205
    public SmartSpritesParameters(String rootDir, List<String> cssFiles,
206
        String outputDir, String documentRootDir, MessageLevel logLevel,
207
        String cssFileSuffix, PngDepth spritePngDepth, boolean spritePngIe6,
208
        String cssEncoding, boolean markSpriteImages)
209
    {
1✔
210
        this.rootDir = rootDir;
1✔
211
        this.cssFiles = cssFiles;
1✔
212
        this.outputDir = outputDir;
1✔
213
        this.documentRootDir = documentRootDir;
1✔
214
        this.logLevel = logLevel;
1✔
215
        this.cssFileEncoding = cssEncoding;
1✔
216
        this.cssFileSuffix = getCssFileSuffix(cssFileSuffix);
1✔
217
        this.spritePngDepth = spritePngDepth;
1✔
218
        this.spritePngIe6 = spritePngIe6;
1✔
219
        this.markSpriteImages = markSpriteImages;
1✔
220
    }
1✔
221

222
    /**
223
     * Validates the provided parameters. All resource paths are resolved against the local
224
     * file system.
225
     * 
226
     * @return <code>true</code> if the parameters are valid
227
     */
228
    public boolean validate(MessageLog log)
229
    {
230
        boolean valid = true;
1✔
231

232
        // Either root dir or css files are required
233
        if (!hasRootDir() && !hasCssFiles())
1✔
234
        {
235
            log.error(MessageType.EITHER_ROOT_DIR_OR_CSS_FILES_IS_REQUIRED);
1✔
236
            return false;
1✔
237
        }
238

239
        // If there is no output dir, we can't have both root dir or css files
240
        if (!hasOutputDir() && hasRootDir() && hasCssFiles())
1✔
241
        {
242
            log.error(MessageType.ROOT_DIR_AND_CSS_FILES_CANNOT_BE_BOTH_SPECIFIED_UNLESS_WITH_OUTPUT_DIR);
1✔
243
            return false;
1✔
244
        }
245

246
        // Check root dir if provided
247
        if (hasRootDir())
1✔
248
        {
249
            final File rootDir = FileUtils.getCanonicalOrAbsoluteFile(this.rootDir);
1✔
250
            if ((!rootDir.exists() || !rootDir.isDirectory()))
1✔
251
            {
252
                log.error(MessageType.ROOT_DIR_DOES_NOT_EXIST_OR_IS_NOT_DIRECTORY,
1✔
253
                    this.rootDir);
254
                valid = false;
1✔
255
            }
256
        }
257

258
        // Check output dir if provided
259
        if (hasOutputDir())
1✔
260
        {
261
            // For output dir, we need root dir
262
            if (!hasRootDir())
1✔
263
            {
264
                log.error(MessageType.ROOT_DIR_IS_REQUIRED_FOR_OUTPUT_DIR);
1✔
265
                return false;
1✔
266
            }
267

268
            final File outputDir = FileUtils.getCanonicalOrAbsoluteFile(this.outputDir);
1✔
269
            if (outputDir.exists() && !outputDir.isDirectory())
1✔
270
            {
271
                log.error(MessageType.OUTPUT_DIR_IS_NOT_DIRECTORY, this.outputDir);
1✔
272
                valid = false;
1✔
273
            }
274
        }
275

276
        if (!hasOutputDir() && StringUtils.isBlank(cssFileSuffix))
1✔
277
        {
278
            log.error(MessageType.CSS_FILE_SUFFIX_IS_REQUIRED_IF_NO_OUTPUT_DIR);
1✔
279
            valid = false;
1✔
280
        }
281

282
        if (hasDocumentRootDir())
1✔
283
        {
284
            final File documentRootDir = FileUtils
1✔
285
                .getCanonicalOrAbsoluteFile(this.documentRootDir);
1✔
286
            if (!documentRootDir.exists() || !documentRootDir.isDirectory())
1✔
287
            {
288
                log.error(
1✔
289
                    MessageType.DOCUMENT_ROOT_DIR_DOES_NOT_EXIST_OR_IS_NOT_DIRECTORY,
290
                    this.documentRootDir);
291
                valid = false;
1✔
292
            }
293
        }
294

295
        return valid;
1✔
296
    }
297

298
    private String getCssFileSuffix(String suffix)
299
    {
300
        if (suffix == null)
1✔
301
        {
302
            if (!hasOutputDir())
1✔
303
            {
304
                // If there is no output dir, we must have some suffix
305
                return DEFAULT_CSS_FILE_SUFFIX;
1✔
306
            }
307
            else
308
            {
309
                // If we have an output dir, we can have an empty suffix
310
                return "";
1✔
311
            }
312
        }
313
        else
314
        {
315
            return suffix;
1✔
316
        }
317
    }
318

319
    public String getRootDir()
320
    {
321
        return rootDir;
1✔
322
    }
323

324
    public File getRootDirFile() throws IOException
325
    {
326
        return rootDir.startsWith("..") ? new File(rootDir).getCanonicalFile()
1✔
327
            : new File(rootDir);
1✔
328
    }
329

330
    public boolean hasRootDir()
331
    {
332
        return StringUtils.isNotBlank(rootDir);
1✔
333
    }
334

335
    public List<String> getCssFiles()
336
    {
337
        return cssFiles;
1✔
338
    }
339

340
    public boolean hasCssFiles()
341
    {
342
        return cssFiles != null && !cssFiles.isEmpty();
1✔
343
    }
344

345
    public String getOutputDir()
346
    {
347
        return outputDir;
1✔
348
    }
349

350
    public boolean hasOutputDir()
351
    {
352
        return StringUtils.isNotBlank(outputDir);
1✔
353
    }
354

355
    public String getDocumentRootDir()
356
    {
357
        return documentRootDir;
1✔
358
    }
359

360
    public boolean hasDocumentRootDir()
361
    {
362
        return StringUtils.isNotBlank(documentRootDir);
1✔
363
    }
364

365
    public MessageLevel getLogLevel()
366
    {
367
        return logLevel;
×
368
    }
369

370
    public String getCssFileSuffix()
371
    {
372
        return cssFileSuffix;
1✔
373
    }
374

375
    public PngDepth getSpritePngDepth()
376
    {
377
        return spritePngDepth;
1✔
378
    }
379

380
    public boolean isSpritePngIe6()
381
    {
382
        return spritePngIe6;
1✔
383
    }
384

385
    public boolean isMarkSpriteImages()
386
    {
387
        return markSpriteImages;
1✔
388
    }
389

390
    public String getCssFileEncoding()
391
    {
392
        return cssFileEncoding;
1✔
393
    }
394
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc