Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package crudini for openSUSE:Factory checked in at 2025-09-12 21:10:00 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/crudini (Old) and /work/SRC/openSUSE:Factory/.crudini.new.1977 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "crudini" Fri Sep 12 21:10:00 2025 rev:11 rq:1304151 version:0.9.6 Changes: -------- --- /work/SRC/openSUSE:Factory/crudini/crudini.changes 2023-11-16 20:31:06.886017498 +0100 +++ /work/SRC/openSUSE:Factory/.crudini.new.1977/crudini.changes 2025-09-12 21:10:20.905297612 +0200 @@ -1,0 +2,21 @@ +Thu Sep 11 20:09:11 UTC 2025 - Dirk Müller <[email protected]> + +- update to 0.9.6: + * Support BOM correctly. Previously we would have stripped + any Byte Order Mark, and incorrectly matched items on the first + line. + * Extraneous blank lines are avoided when deleting a section. + * Previously blank lines preceeding a [section] were not + removed. + * Support creating a section called "default". Previously + this would have been disallowed, with an invalid section name + error. + * Support ensuring a single space in all 'name = value' + entries in the file with --ini-options=space. This is + symmetric and opposite to the existing --ini-options=nospace + option. + * Support ensuring a single blank line between sections, and + no blank lines at the start or end of the file, with --ini- + options=sectionspace. + +------------------------------------------------------------------- Old: ---- crudini-0.9.5.tar.gz New: ---- crudini-0.9.6.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ crudini.spec ++++++ --- /var/tmp/diff_new_pack.eTOzZu/_old 2025-09-12 21:10:21.473321564 +0200 +++ /var/tmp/diff_new_pack.eTOzZu/_new 2025-09-12 21:10:21.473321564 +0200 @@ -1,7 +1,7 @@ # # spec file for package crudini # -# Copyright (c) 2023 SUSE LLC +# Copyright (c) 2025 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: crudini -Version: 0.9.5 +Version: 0.9.6 Release: 0 Summary: A utility for manipulating ini files License: GPL-2.0-only ++++++ crudini-0.9.5.tar.gz -> crudini-0.9.6.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crudini-0.9.5/EXAMPLES new/crudini-0.9.6/EXAMPLES --- old/crudini-0.9.5/EXAMPLES 2023-10-03 15:50:11.000000000 +0200 +++ new/crudini-0.9.6/EXAMPLES 2025-04-16 16:44:05.000000000 +0200 @@ -60,5 +60,9 @@ # Add/Update a var, ensuring complete file in name=value format crudini --ini-options=nospace --set config_file section parameter value +# Rewrite ini file to ensure a single blank line between sections, +# and no leading or trailing blank lines + crudini --ini-options=sectionspace --set config_file "" + # Read indented ini file, like .gitconfig crudini --ini-options=ignoreindent --format=lines --get ~/.gitconfig diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crudini-0.9.5/INSTALL new/crudini-0.9.6/INSTALL --- old/crudini-0.9.5/INSTALL 2022-07-19 16:24:05.000000000 +0200 +++ new/crudini-0.9.6/INSTALL 2025-04-16 17:04:00.000000000 +0200 @@ -23,3 +23,10 @@ dependency is appropriately installed on your system. You can also download and run the single crudini.py file directly to use latest version. + +On any system you should be able to pip install +the latest code from github like: + +``` +pip install git+https://github.com/pixelb/crudini.git#egg=crudini +``` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crudini-0.9.5/Makefile new/crudini-0.9.6/Makefile --- old/crudini-0.9.5/Makefile 2023-10-04 11:51:36.000000000 +0200 +++ new/crudini-0.9.6/Makefile 2025-04-16 17:18:45.000000000 +0200 @@ -1,5 +1,5 @@ name = crudini -version = 0.9.5 +version = 0.9.6 all: help2man -n "manipulate ini files" -o crudini.1 -N ./crudini-help diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crudini-0.9.5/NEWS new/crudini-0.9.6/NEWS --- old/crudini-0.9.5/NEWS 2023-10-03 16:53:15.000000000 +0200 +++ new/crudini-0.9.6/NEWS 2025-04-16 17:19:43.000000000 +0200 @@ -1,6 +1,26 @@ crudini NEWS -*- outline -*- -* Noteworthy changes in release 0.9.5 (????-??-??) +* Noteworthy changes in release 0.9.6 (2025-04-16) + + Support BOM correctly. Previously we would have stripped any + Byte Order Mark, and incorrectly matched items on the first line. + + Extraneous blank lines are avoided when deleting a section. + Previously blank lines preceeding a [section] were not removed. + Note this will collapse multiple empty lines preceding all sections. + + Support creating a section called "default". Previously this + would have been disallowed, with an invalid section name error. + + Support ensuring a single space in all 'name = value' entries in the file + with --ini-options=space. This is symmetric and opposite to the existing + --ini-options=nospace option. + + Support ensuring a single blank line between sections, and no blank lines + at the start or end of the file, with --ini-options=sectionspace. + + +* Noteworthy changes in release 0.9.5 (2023-10-04) ** Improvements diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crudini-0.9.5/README.md new/crudini-0.9.6/README.md --- old/crudini-0.9.5/README.md 2023-10-04 11:52:00.000000000 +0200 +++ new/crudini-0.9.6/README.md 2025-04-16 17:23:01.000000000 +0200 @@ -24,6 +24,8 @@ Formats are 'sh','ini','lines' --ini-options=OPT Set options for handling ini files. Options are: 'nospace': use format name=value not name = value + 'space': ensure name = value format + 'sectionspace': ensure one blank line between sections 'ignoreindent': ignore leading whitespace --inplace Lock and write files in place. This is not atomic but has less restrictions @@ -100,6 +102,10 @@ # Add/Update a var, ensuring complete file in name=value format crudini --ini-options=nospace --set config_file section parameter value +# Rewrite ini file to ensure a single blank line between sections, +# and no leading or trailing blank lines + crudini --ini-options=sectionspace --set config_file "" + # Read indented ini file, like .gitconfig crudini --ini-options=ignoreindent --format=lines --get ~/.gitconfig ``` @@ -128,3 +134,10 @@ dependency is appropriately installed on your system. You can also download and run the single crudini.py file directly to use latest version. + +On any system you should be able to pip install +the latest code from github like: + +``` +pip install git+https://github.com/pixelb/crudini.git#egg=crudini +``` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crudini-0.9.5/crudini.1 new/crudini-0.9.6/crudini.1 --- old/crudini-0.9.5/crudini.1 2023-10-04 11:52:00.000000000 +0200 +++ new/crudini-0.9.6/crudini.1 2025-04-16 17:23:01.000000000 +0200 @@ -1,5 +1,5 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH CRUDINI "1" "October 2023" "crudini 0.9.5" "User Commands" +.TH CRUDINI "1" "April 2025" "crudini 0.9.6" "User Commands" .SH NAME crudini \- manipulate ini files .SH SYNOPSIS @@ -36,6 +36,8 @@ \fB\-\-ini\-options\fR=\fI\,OPT\/\fR Set options for handling ini files. Options are: \&'nospace': use format name=value not name = value +\&'space': ensure name = value format +\&'sectionspace': ensure one blank line between sections \&'ignoreindent': ignore leading whitespace .TP \fB\-\-inplace\fR @@ -143,6 +145,11 @@ .IP crudini \-\-ini\-options=nospace \-\-set config_file section parameter value .PP +# Rewrite ini file to ensure a single blank line between sections, +# and no leading or trailing blank lines +.IP +crudini \-\-ini\-options=sectionspace \-\-set config_file "" +.PP # Read indented ini file, like .gitconfig .IP crudini \-\-ini\-options=ignoreindent \-\-format=lines \-\-get ~/.gitconfig diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crudini-0.9.5/crudini.py new/crudini-0.9.6/crudini.py --- old/crudini-0.9.5/crudini.py 2023-10-04 11:42:39.000000000 +0200 +++ new/crudini-0.9.6/crudini.py 2025-04-16 17:18:35.000000000 +0200 @@ -16,6 +16,7 @@ import getopt import hashlib import iniparse +import io import os import re import shutil @@ -24,14 +25,31 @@ if sys.version_info[0] >= 3: import shlex as pipes - from io import StringIO import configparser else: + import codecs import pipes - from cStringIO import StringIO import ConfigParser as configparser +user_encoding = 'utf-8' # user specified items +file_encoding = 'utf-8' # encoding of ini file contents + + +# Python 2/3 wrapper to convert strings to unicode +try: # Python 2 + unicode + + def s2u(s, e=user_encoding): + return unicode(s, e) + # Also add conversion wrapper for print() + sys.stdout = codecs.getwriter(user_encoding)(sys.stdout) +except NameError: # Python 3 + def s2u(s, e=user_encoding): + return str(s) + unicode = str + + def error(message=None): if message: sys.stderr.write(message + '\n') @@ -73,6 +91,7 @@ self.last_section = 'DEFAULT' self.section_indents = {} self.windows_eol = None + self.bom = None # Note [ \t] used rather than \s to avoid adjusting \r\n when no value # Unicode spacing around the delimiter would be very unusual anyway self.delimiter_spacing = re.compile(r'(.*?)[ \t]*([:=])[ \t]*(.*)') @@ -83,6 +102,16 @@ def readline(self): line = self.fp.readline() + + # Strip BOM. iniparse tracks it but simpler for us to replace later + # as we're munging the data in various ways. + if self.bom is None: + if line and line[0] == u'\ufeff': + line = line[1:] + self.bom = True + else: + self.bom = False + # XXX: This doesn't handle ;inline comments. # Really should be done within iniparse. @@ -123,6 +152,10 @@ # But if need to remove the spacing, then should for all params line = self.delimiter_spacing.sub(r'\1\2\3', line) + elif not section and 'space' in self.iniopt: + # Convert _all_ existing params. New params will be correct + + line = self.delimiter_spacing.sub(r'\1 \2 \3', line) if line[0] in ' \t': self.indented = True @@ -148,7 +181,7 @@ def readline(self): if self.first: self.first = False - return '[%s]' % iniparse.DEFAULTSECT + return s2u('[%s]' % iniparse.DEFAULTSECT) else: return CrudiniInputFilter.readline(self) @@ -214,7 +247,6 @@ atexit.register(self.delete) open_mode = os.O_RDONLY - open_args = {} if operation != "--get": # We're only reading here, but we check now for write # permissions we'll need in --inplace case to avoid @@ -225,13 +257,11 @@ if create and operation != '--del': open_mode += os.O_CREAT - # Don't convert line endings, so we maintain CRLF in files - if sys.version_info[0] >= 3: - open_args = {'newline': ''} - try: - self.fp = os.fdopen(os.open(self.filename, open_mode, 0o666), - **open_args) + # Note we open in binary mode to avoid newline processing, + # and also to give more control over the decoding process later. + # This avoids platform encoding inconsistencies as per PEP 597. + self.fp = os.fdopen(os.open(self.filename, open_mode, 0o666), 'rb') if inplace: # In general readers (--get) are protected by file_replace(), # but using read lock here gives AC of the ACID properties @@ -243,7 +273,7 @@ while True: self.lock() fpnew = os.fdopen(os.open(self.filename, open_mode, 0o666), - **open_args) + 'rb') if (os.name == 'nt' or os.path.sameopenfile(self.fp.fileno(), fpnew.fileno())): # Note we don't fpnew.close() here as that would break @@ -262,7 +292,7 @@ # We don't exit early here so that --verbose is also handled. if create and operation == '--del' \ and e.errno in (errno.ENOTDIR, errno.ENOENT): - self.fp = StringIO('') + self.fp = io.BytesIO(b'') else: error(str(e)) sys.exit(1) @@ -289,7 +319,7 @@ # We ignore lines starting with '%' which mercurial uses to include iniparse.change_comment_syntax('%;#', allow_rem=False) if preserve_case: - self.optionxform = str + self.optionxform = lambda x: x # Adjust iniparse separator to default to no space around equals # Note this does NOT convert existing params with spaces, # that's done in CrudiniInputFilter.readline(). @@ -413,6 +443,8 @@ data = None conf = None added_default_section = False + default_adjust = False + removed_section = False ini_section_blanks = [] _print = None @@ -465,10 +497,8 @@ st = os.stat(name) os.fchown(f, st.st_uid, st.st_gid) - if sys.version_info[0] >= 3: - os.write(f, bytearray(data, 'utf-8')) - else: - os.write(f, data) + os.write(f, bytearray(data, file_encoding)) + # We assume the existing file is persisted, # so sync here to ensure new data is persisted # before referencing it. Otherwise the metadata could @@ -512,13 +542,9 @@ - Less Durable as existing data truncated before I/O completes. - Requires write access to file rather than write access to dir. """ - # Don't convert line endings, so we maintain CRLF in files - open_args = {} - if sys.version_info[0] >= 3: - open_args = {'newline': ''} - with open(name, 'w', **open_args) as f: - f.write(data) + with open(name, 'wb') as f: + f.write(bytearray(data, file_encoding)) f.flush() os.fsync(f.fileno()) @@ -602,6 +628,8 @@ Formats are 'sh','ini','lines' --ini-options=OPT Set options for handling ini files. Options are: 'nospace': use format name=value not name = value + 'space': ensure name = value format + 'sectionspace': ensure one blank line between sections 'ignoreindent': ignore leading whitespace --inplace Lock and write files in place. This is not atomic but has less restrictions @@ -623,9 +651,12 @@ try: self.mode = operation[0] self.cfgfile = operation[1] - self.section = operation[2] - self.param = operation[3] - self.value = operation[4] + # Convert the following to unicode as + # we process in unicode explicitly in python2. + # Not needed on python3 where all strings are unicode. + self.section = s2u(operation[2]) + self.param = s2u(operation[3]) + self.value = s2u(operation[4]) except IndexError: pass @@ -693,7 +724,7 @@ if o in ('--help',): self.usage(0) elif o in ('--version',): - print('crudini 0.9.5') + print('crudini 0.9.6') sys.exit(0) elif o in ('--verbose',): self.verbose = True @@ -705,9 +736,13 @@ elif o in ('--ini-options',): self.iniopt = a.split(',') for opt in self.iniopt: - if opt not in ('', 'nospace', 'ignoreindent'): + if opt not in ('', 'nospace', 'space', 'sectionspace', + 'ignoreindent'): error('--ini-options not recognized: %s' % opt) self.usage(1) + if 'nospace' in self.iniopt and 'space' in self.iniopt: + error('--ini-options=space,nospace are mutually exclusive') + sys.exit(1) elif o in ('--existing',): self.update = a or 'param' # 'param' implies all must exist if self.update not in ('file', 'section', 'param'): @@ -804,11 +839,13 @@ sys.exit(1) # A "param=with=equals = value" line can not be found with --get - # so avoid the ambiguity. Restrict to 'nospace' to allow hack in - # https://github.com/pixelb/crudini/issues/33#issuecomment-\ + # so avoid the ambiguity. Note this precludes the "nospace" hack + # in https://github.com/pixelb/crudini/issues/33#issuecomment-\ # 1151253988 - if 'nospace' in self.iniopt and self.param and '=' in self.param: + if self.param and '=' in self.param: error("param names should not contain '=': %s" % self.param) + if 'nospace' not in self.iniopt: + error("Use --ini-options=nospace if you want that format") sys.exit(1) if self.section_explicit_default is None: @@ -825,7 +862,7 @@ return operations def _has_default_section(self): - fp = StringIO(self.data) + fp = io.StringIO(self.data) for line in fp: if line.startswith('[%s]' % iniparse.DEFAULTSECT): return True @@ -833,10 +870,7 @@ def _chksum(self, data): h = hashlib.sha256() - if sys.version_info[0] >= 3: - h.update(bytearray(data, 'utf-8')) - else: - h.update(data) + h.update(bytearray(data, file_encoding)) return h.digest() def _parse_file(self, filename, add_default=False, preserve_case=False): @@ -846,9 +880,10 @@ # Doing it here will avoid rereads on reparse and support # correct parsing of stdin if filename == '-': - self.data = sys.stdin.read() + ifp = os.fdopen(sys.stdin.fileno(), 'rb') else: - self.data = self.locked_file.fp.read() + ifp = self.locked_file.fp + self.data = ifp.read().decode(file_encoding) if self.mode != '--get': # compare checksums to flag any changes # (even spacing or case adjustments) with --verbose, @@ -860,7 +895,8 @@ else: self.newline_at_start = False - fp = StringIO(self.data) + # newline='' =-> don't convert line endings + fp = io.StringIO(self.data, newline='') if add_default: fp = AddDefaultSection(fp, self.iniopt) else: @@ -875,6 +911,7 @@ self.replace_leading = fp.replace_leading self.section_indents = fp.section_indents self.windows_eol = fp.windows_eol + self.bom = fp.bom return conf except EnvironmentError as e: error(str(e)) @@ -961,12 +998,21 @@ if self.mode == "--del": return else: + # Adjust to allow adding a "default" section (issue #80) + skip_section_add = False + if section.lower() == "default": + section = "crudini_default_adjust_%s" % section + self.default_adjust = True + if self.conf.has_section(section): # We already added + skip_section_add = True + # Note this always adds a '\n' before the section name # resulting in double spaced sections or blank line at # the start of a new file to which a new section is added. # List the sections here to adjust when writing. - self.ini_section_blanks.append(section) - self.conf.add_section(section) + if not skip_section_add: + self.ini_section_blanks.append(section) + self.conf.add_section(section) if param is not None: try: @@ -1048,9 +1094,11 @@ for name in self.conf.defaults(): self.conf.remove_option(iniparse.DEFAULTSECT, name) else: - if not self.conf.remove_section(self.section) \ - and self.update in ('param', 'section'): - raise configparser.NoSectionError(self.section) + if not self.conf.remove_section(self.section): + if self.update in ('param', 'section'): + raise configparser.NoSectionError(self.section) + else: + self.removed_section = True elif self.value is None: try: if not self.conf.remove_option(self.section, self.param) \ @@ -1180,9 +1228,18 @@ self.command_get() if self.mode != '--get': + # Del possible extraneous blank line left with removed section + # XXX: This may collapse existing multiple blank lines + if self.removed_section and 'sectionspace' not in self.iniopt: + iniparse.tidy(self.conf) + # XXX: Ideally we should just do conf.write(f) here, but to # avoid iniparse issues, we massage the data a little here - str_data = str(self.conf.data) + if sys.version_info[0] >= 3: + str_data = str(self.conf.data) + else: + # XXX: Can't use uc() here as can't specify encoding + str_data = unicode(self.conf.data) if len(str_data) and str_data[-1] != '\n': str_data += '\n' @@ -1210,11 +1267,21 @@ else: str_data = str_data.replace(default_sect, '', 1) - # Remove extraneous blanks added by iniparse. - # Note iniparse also has a tidy() function to do globally - for section in self.ini_section_blanks: - section_s = '\n[%s]\n' % section - str_data = str_data.replace(section_s, section_s[1:], 1) + # Handle creation of non special "default" section + if self.default_adjust: + str_data = str_data.replace('crudini_default_adjust_', '') + + # Process blank lines around sections + if 'sectionspace' in self.iniopt: + # Ensure a single blank line before sections + str_data = re.sub(r'\n*(\[[^\]]+\])', r'\n\n\1', str_data) + str_data = str_data.lstrip('\n') # remove leading \n + str_data = str_data.rstrip('\n') + '\n' # ensure \n at end + else: + # Remove extraneous blanks iniparse adds when adding sects + for section in self.ini_section_blanks: + section_ = '\n[%s]\n' % section + str_data = str_data.replace(section_, section_[1:], 1) if self.windows_eol: # iniparse uses '\n' for new/updated items @@ -1230,6 +1297,9 @@ str_data = str_data.replace('%s=%scrudini_no_arg' % (spacing, spacing), '') + if self.bom: + str_data = u'\ufeff%s' % str_data + changed = self.chksum != self._chksum(str_data) if self.output == '-': diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crudini-0.9.5/setup.cfg new/crudini-0.9.6/setup.cfg --- old/crudini-0.9.5/setup.cfg 2023-10-04 11:42:26.000000000 +0200 +++ new/crudini-0.9.6/setup.cfg 2025-04-16 17:18:25.000000000 +0200 @@ -3,7 +3,7 @@ author = Pádraig Brady author_email = [email protected] license = GPLv2 -version = 0.9.5 +version = 0.9.6 description = A utility for manipulating ini files keywords = ini, config, edit url = http://github.com/pixelb/crudini diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crudini-0.9.5/tests/space-in.ini new/crudini-0.9.6/tests/space-in.ini --- old/crudini-0.9.5/tests/space-in.ini 1970-01-01 01:00:00.000000000 +0100 +++ new/crudini-0.9.6/tests/space-in.ini 2025-04-16 13:49:15.000000000 +0200 @@ -0,0 +1,8 @@ +#comment=ignore +p1=1 +p2=2=2 +p3:3=3 +p 4=4 +p5 = 5 +p6:6:6 a + multiline=ignore diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crudini-0.9.5/tests/space-out.ini new/crudini-0.9.6/tests/space-out.ini --- old/crudini-0.9.5/tests/space-out.ini 1970-01-01 01:00:00.000000000 +0100 +++ new/crudini-0.9.6/tests/space-out.ini 2025-04-16 13:49:15.000000000 +0200 @@ -0,0 +1,9 @@ +#comment=ignore +p1 = 1 +p2 = 2=2 +p3 : 3=3 +p 4 = 4 +p5 = 5 +p6 : 6:6 a + multiline=ignore +new = val diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crudini-0.9.5/tests/test.sh new/crudini-0.9.6/tests/test.sh --- old/crudini-0.9.5/tests/test.sh 2023-10-03 17:26:02.000000000 +0200 +++ new/crudini-0.9.6/tests/test.sh 2025-04-16 17:16:21.000000000 +0200 @@ -54,25 +54,27 @@ printf '%s\n' '[nonDEFAULT]' 'name = val' > good.ini diff -u test.ini good.ini && ok || fail -printf '%s\n' 'global=val' > test.ini -crudini --set test.ini '' global valnew -printf '%s\n' 'global=valnew' > good.ini -diff -u test.ini good.ini && ok || fail +for bom in '' $'\xef\xbb\xbf'; do + printf '%s%s\n' "$bom" 'global=val' > test.ini + crudini --set test.ini '' global valnew + printf '%s%s\n' "$bom" 'global=valnew' > good.ini + diff -u test.ini good.ini && ok || fail -printf '%s\n' 'global=val' > test.ini -crudini --set test.ini DEFAULT global valnew -printf '%s\n' '[DEFAULT]' 'global=valnew' > good.ini -diff -u test.ini good.ini && ok || fail + printf '%s%s\n' "$bom" 'global=val' > test.ini + crudini --set test.ini DEFAULT global valnew + printf '%s%s\n' "$bom" '[DEFAULT]' 'global=valnew' > good.ini + diff -u test.ini good.ini && ok || fail -printf '%s\n' '[DEFAULT]' 'global=val' > test.ini -crudini --set test.ini DEFAULT global valnew -printf '%s\n' '[DEFAULT]' 'global=valnew' > good.ini -diff -u test.ini good.ini && ok || fail + printf '%s%s\n' "$bom" '[DEFAULT]' 'global=val' > test.ini + crudini --set test.ini DEFAULT global valnew + printf '%s%s\n' "$bom" '[DEFAULT]' 'global=valnew' > good.ini + diff -u test.ini good.ini && ok || fail -printf '%s\n' 'global=val' '' '[nonDEFAULT]' 'name=val' > test.ini -crudini --set test.ini '' global valnew -printf '%s\n' 'global=valnew' '' '[nonDEFAULT]' 'name=val' > good.ini -diff -u test.ini good.ini && ok || fail + printf '%s%s\n' "$bom" 'global=val' '' '[nonDEFAULT]' 'name=val' > test.ini + crudini --set test.ini '' global valnew + printf '%s%s\n' "$bom" 'global=valnew' '' '[nonDEFAULT]' 'name=val' > good.ini + diff -u test.ini good.ini && ok || fail +done # do these --sets which test [DEFAULT] handling also with --inplace for mode in '' '--inplace'; do @@ -186,6 +188,9 @@ # basic get test "$(crudini --get example.ini section1 cAps)" = 'not significant' && ok || fail +# unicode get +test "$(crudini --get example.ini non-sh-compat útf8name)" = 'val' && ok || fail + # get sections crudini --get example.ini > test.ini printf '%s\n' DEFAULT section1 'empty section' non-sh-compat list > good.ini @@ -541,6 +546,10 @@ test "$(crudini --ini-options=nospace --output=- --set noequals.ini \ noequals param1 value1 \ | grep param1)" = 'param1=value1' && ok || fail +# Ensure correct spacing with --ini-options=space +test "$(crudini --ini-options=space --output=- --set noequals.ini \ + noequals param1 value1 \ + | grep param1)" = 'param1 = value1' && ok || fail # Test can read windows format files printf '%s\r\n' '' 'empty' 'param=value' > test.ini @@ -570,6 +579,13 @@ diff -u <(crudini --output=- --ini-options=nospace \ --set nospace-in.ini '' new val) \ nospace-out.ini && ok || fail +# Test --ini-options=space +diff -u <(crudini --output=- --ini-options=space \ + --set space-out.ini '' new val) \ + space-out.ini && ok || fail +# - Mixed space / nospace not allowed +crudini --get file.conf '' param1 --ini-options=space,nospace \ + 2>/dev/null && fail || ok # Test multi operation # - Multiple set @@ -674,3 +690,29 @@ --set file.conf '' ' param1' a && ok || fail diff -u good.conf file.conf && ok || fail rm file.conf good.conf + +# Test removal of extraneous empty lines +# implicitly enabled with --del +printf '\n[%s]\n' 1 2 > good.conf +cp good.conf file.conf +for i in 1 2; do crudini --del file.conf $i; crudini --set file.conf $i; done +diff -u good.conf file.conf && ok || fail +rm file.conf good.conf + +# Test addition/removal of empty lines with sectionspace +printf '\n[%s]\n[%s]\n\n[%s]\n\n\n[%s]\n\n' 1 2 3 4 > file.conf +printf '[%s]\n\n[%s]\n\n[%s]\n\n[%s]\n' 1 2 3 4 > good.conf +crudini --set --ini-options=sectionspace file.conf '' +diff -u good.conf file.conf && ok || fail +rm file.conf good.conf + +# Test creation of a "default" section +printf '[%s]\n' 'default' > good.conf +crudini --set file.conf default # new +diff -u good.conf file.conf && ok || fail +crudini --set file.conf default # existing +diff -u good.conf file.conf && ok || fail +rm file.conf +crudini --set file.conf default --set file.conf default # double new +diff -u good.conf file.conf && ok || fail +rm file.conf good.conf
