diff --git a/README.md b/README.md
index 2468846..6d03af1 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ Note: Currently the focus is abstractions with a focus on handling Apache config
## Instructions
-### Ccopy Native wrapper library
+### Copy Native wrapper library
`cd Sharp.Augeas && ./copyLibrary.sh`
diff --git a/Sharp.Augeas.Test/AugeasTests.cs b/Sharp.Augeas.Test/AugeasTests.cs
new file mode 100644
index 0000000..7e14622
--- /dev/null
+++ b/Sharp.Augeas.Test/AugeasTests.cs
@@ -0,0 +1,43 @@
+namespace Sharp.Augeas.Test;
+
+public class AugeasTests
+{
+ private Augeas _augeas;
+
+ [SetUp]
+ public void Setup()
+ {
+ var rootDir = Environment.CurrentDirectory + "/root";
+ var lensDir = Environment.CurrentDirectory + "/lens";
+ _augeas = new Augeas(new AugSettings(rootDir, lensDir));
+ }
+
+ [Test]
+ public void NoExceptionThrownWhenPrintingVirtualhostTree()
+ {
+ var virtualHostConfig = "/etc/apache2/sites-available/00-ci.codeliturgy.com.conf";
+ _augeas.PrintVirtualHostTree(virtualHostConfig);
+ Assert.Pass();
+ }
+
+
+ [Test]
+ public void NoExceptionThrownWhenPrintingPreview()
+ {
+ var virtualHostConfig = "/etc/apache2/sites-available/00-ci.codeliturgy.com.conf";
+ _augeas.PrintPreview(virtualHostConfig);
+ Assert.Pass();
+
+ }
+
+ [Test]
+ public void GetTreeVirtualHostReturnsDictionaryWithKeys()
+ {
+ var virtualHostConfig = "/etc/apache2/sites-available/00-ci.codeliturgy.com.conf";
+ var tree = _augeas.GetVirtualHostTree(virtualHostConfig);
+ Assert.That(tree.Count > 0);
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/Sharp.Augeas.Test/Platform/Linux/libclAugeas.so b/Sharp.Augeas.Test/Platform/Linux/libclAugeas.so
new file mode 100644
index 0000000..6903728
Binary files /dev/null and b/Sharp.Augeas.Test/Platform/Linux/libclAugeas.so differ
diff --git a/Sharp.Augeas.Test/Sharp.Augeas.Test.csproj b/Sharp.Augeas.Test/Sharp.Augeas.Test.csproj
new file mode 100644
index 0000000..7e3509a
--- /dev/null
+++ b/Sharp.Augeas.Test/Sharp.Augeas.Test.csproj
@@ -0,0 +1,38 @@
+
+
+
+ net6.0
+ enable
+ disable
+ true
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+ root\%(RecursiveDir)\%(Filename)%(Extension)
+
+
+
+
+ PreserveNewest
+ lens\%(RecursiveDir)\%(Filename)%(Extension)
+
+
+
+
diff --git a/Sharp.Augeas.Test/Usings.cs b/Sharp.Augeas.Test/Usings.cs
new file mode 100644
index 0000000..3244567
--- /dev/null
+++ b/Sharp.Augeas.Test/Usings.cs
@@ -0,0 +1 @@
+global using NUnit.Framework;
diff --git a/Sharp.Augeas/copyLibrary.sh b/Sharp.Augeas.Test/copyLibrary.sh
similarity index 100%
rename from Sharp.Augeas/copyLibrary.sh
rename to Sharp.Augeas.Test/copyLibrary.sh
diff --git a/Sharp.Augeas.Test/lens/access.aug b/Sharp.Augeas.Test/lens/access.aug
new file mode 100644
index 0000000..39920d3
--- /dev/null
+++ b/Sharp.Augeas.Test/lens/access.aug
@@ -0,0 +1,128 @@
+(*
+Module: Access
+ Parses /etc/security/access.conf
+
+Author: Lorenzo Dalrio
+
+About: Reference
+ Some examples of valid entries can be found in access.conf or "man access.conf"
+
+About: License
+ This file is licensed under the LGPL v2+, like the rest of Augeas.
+
+About: Lens Usage
+ Sample usage of this lens in augtool
+
+ * Add a rule to permit login of all users from local sources (tty's, X, cron)
+ > set /files/etc/security/access.conf[0] +
+ > set /files/etc/security/access.conf[0]/user ALL
+ > set /files/etc/security/access.conf[0]/origin LOCAL
+
+About: Configuration files
+ This lens applies to /etc/security/access.conf. See .
+
+About: Examples
+ The file contains various examples and tests.
+*)
+module Access =
+ autoload xfm
+
+(* Group: Comments and empty lines *)
+(* Variable: comment *)
+let comment = Util.comment
+(* Variable: empty *)
+let empty = Util.empty
+
+(* Group: Useful primitives *)
+(* Variable: colon
+ * this is the standard field separator " : "
+ *)
+let colon = del (Rx.opt_space . ":" . Rx.opt_space) " : "
+
+
+(************************************************************************
+ * Group: ENTRY LINE
+ *************************************************************************)
+(* View: access
+ * Allow (+) or deny (-) access
+ *)
+let access = label "access" . store /[+-]/
+
+(* Variable: identifier_re
+ Regex for user/group identifiers *)
+let identifier_re = /[A-Za-z0-9_.\\-]+/
+
+(* View: user_re
+ * Regex for user/netgroup fields
+ *)
+let user_re = identifier_re - /[Ee][Xx][Cc][Ee][Pp][Tt]/
+
+(* View: user
+ * user can be a username, username@hostname or a group
+ *)
+let user = [ label "user"
+ . ( store user_re
+ | store Rx.word . Util.del_str "@"
+ . [ label "host" . store Rx.word ] ) ]
+
+(* View: group
+ * Format is (GROUP)
+ *)
+let group = [ label "group"
+ . Util.del_str "(" . store identifier_re . Util.del_str ")" ]
+
+(* View: netgroup
+ * Format is @NETGROUP[@@NISDOMAIN]
+ *)
+let netgroup =
+ [ label "netgroup" . Util.del_str "@" . store user_re
+ . [ label "nisdomain" . Util.del_str "@@" . store Rx.word ]? ]
+
+(* View: user_list
+ * A list of users or netgroups to apply the rule to
+ *)
+let user_list = Build.opt_list (user|group|netgroup) Sep.space
+
+(* View: origin_list
+ * origin_list can be a single ipaddr/originname/domain/fqdn or a list of those values
+ *)
+let origin_list =
+ let origin_re = Rx.no_spaces - /[Ee][Xx][Cc][Ee][Pp][Tt]/
+ in Build.opt_list [ label "origin" . store origin_re ] Sep.space
+
+(* View: except
+ * The except operator makes it possible to write very compact rules.
+ *)
+let except (lns:lens) = [ label "except" . Sep.space
+ . del /[Ee][Xx][Cc][Ee][Pp][Tt]/ "EXCEPT"
+ . Sep.space . lns ]
+
+(* View: entry
+ * A valid entry line
+ * Definition:
+ * > entry ::= access ':' user ':' origin_list
+ *)
+let entry = [ access . colon
+ . user_list
+ . (except user_list)?
+ . colon
+ . origin_list
+ . (except origin_list)?
+ . Util.eol ]
+
+(************************************************************************
+ * Group: LENS & FILTER
+ *************************************************************************)
+(* View: lns
+ The access.conf lens, any amount of
+ * lines
+ *
+ *
+*)
+let lns = (comment|empty|entry) *
+
+(* Variable: filter *)
+let filter = incl "/etc/security/access.conf"
+
+(* xfm *)
+let xfm = transform lns filter
diff --git a/Sharp.Augeas.Test/lens/activemq_conf.aug b/Sharp.Augeas.Test/lens/activemq_conf.aug
new file mode 100644
index 0000000..191d811
--- /dev/null
+++ b/Sharp.Augeas.Test/lens/activemq_conf.aug
@@ -0,0 +1,61 @@
+(*
+Module: ActiveMQ_Conf
+ ActiveMQ / FuseMQ conf module for Augeas
+
+Author: Brian Redbeard
+
+About: Reference
+ This lens ensures that conf files included in ActiveMQ /FuseMQ are properly
+ handled by Augeas.
+
+About: License
+ This file is licensed under the LGPL License.
+
+About: Lens Usage
+ Sample usage of this lens in augtool:
+
+ * Get your current setup
+ > print /files/etc/activemq.conf
+ ...
+
+ * Change ActiveMQ Home
+ > set /files/etc/activemq.conf/ACTIVEMQ_HOME /usr/share/activemq
+
+ Saving your file:
+
+ > save
+
+About: Configuration files
+ This lens applies to relevant conf files located in /etc/activemq/ and
+ the file /etc/activemq.conf . See .
+
+*)
+
+module ActiveMQ_Conf =
+ autoload xfm
+
+(* Variable: blank_val *)
+let blank_val = del /^\z/
+
+(* View: entry *)
+let entry =
+ Build.key_value_line Rx.word Sep.space_equal Quote.any_opt
+
+(* View: empty_entry *)
+let empty_entry = Build.key_value_line Rx.word Sep.equal Quote.dquote_opt_nil
+
+(* View: lns *)
+let lns = (Util.empty | Util.comment | entry | empty_entry )*
+
+(* Variable: filter *)
+let filter = incl "/etc/activemq.conf"
+ . incl "/etc/activemq/*"
+ . excl "/etc/activemq/*.xml"
+ . excl "/etc/activemq/jmx.*"
+ . excl "/etc/activemq/jetty-realm.properties"
+ . excl "/etc/activemq/*.ts"
+ . excl "/etc/activemq/*.ks"
+ . excl "/etc/activemq/*.cert"
+ . Util.stdexcl
+
+let xfm = transform lns filter
diff --git a/Sharp.Augeas.Test/lens/activemq_xml.aug b/Sharp.Augeas.Test/lens/activemq_xml.aug
new file mode 100644
index 0000000..df2a222
--- /dev/null
+++ b/Sharp.Augeas.Test/lens/activemq_xml.aug
@@ -0,0 +1,41 @@
+(*
+Module: ActiveMQ_XML
+ ActiveMQ / FuseMQ XML module for Augeas
+
+Author: Brian Redbeard
+
+About: Reference
+ This lens ensures that XML files included in ActiveMQ / FuseMQ are properly
+ handled by Augeas.
+
+About: License
+ This file is licensed under the LGPL License.
+
+About: Lens Usage
+ Sample usage of this lens in augtool:
+
+ * Get your current setup
+ > print /files/etc/activemq/activemq.xml
+ ...
+
+ * Change OpenShift domain
+ > set /files/etc/openshift/broker.conf/CLOUD_DOMAIN ose.example.com
+
+ Saving your file:
+
+ > save
+
+About: Configuration files
+ This lens applies to relevant XML files located in /etc/activemq/ . See .
+
+*)
+
+module ActiveMQ_XML =
+ autoload xfm
+
+let lns = Xml.lns
+
+let filter = (incl "/etc/activemq/*.xml")
+ . Util.stdexcl
+
+let xfm = transform lns filter
diff --git a/Sharp.Augeas.Test/lens/afs_cellalias.aug b/Sharp.Augeas.Test/lens/afs_cellalias.aug
new file mode 100644
index 0000000..6b67675
--- /dev/null
+++ b/Sharp.Augeas.Test/lens/afs_cellalias.aug
@@ -0,0 +1,60 @@
+(*
+Module: AFS_cellalias
+ Parses AFS configuration file CellAlias
+
+Author: Pat Riehecky
+
+About: Reference
+ This lens is targeted at the OpenAFS CellAlias file
+
+About: Lens Usage
+ Sample usage of this lens in augtool
+
+ * Add a CellAlias for fnal.gov/files to fnal-files
+ > set /files/usr/vice/etc/CellAlias/target[99] fnal.gov/files
+ > set /files/usr/vice/etc/CellAlias/target[99]/linkname fnal-files
+
+About: License
+ This file is licensed under the LGPL v2+, like the rest of Augeas.
+*)
+
+module AFS_cellalias =
+ autoload xfm
+
+ (************************************************************************
+ * Group: USEFUL PRIMITIVES
+ *************************************************************************)
+
+ (* Group: Comments and empty lines *)
+
+ (* View: eol *)
+ let eol = Util.eol
+ (* View: comment *)
+ let comment = Util.comment
+ (* View: empty *)
+ let empty = Util.empty
+
+ (* Group: separators *)
+
+ (* View: space
+ * Separation between key and value
+ *)
+ let space = Util.del_ws_spc
+ let target = /[^ \t\n#]+/
+ let linkname = Rx.word
+
+ (************************************************************************
+ * Group: ENTRIES
+ *************************************************************************)
+
+ (* View: entry *)
+ let entry = [ label "target" . store target . space . [ label "linkname" . store linkname . eol ] ]
+
+ (* View: lns *)
+ let lns = (empty | comment | entry)*
+
+ let xfm = transform lns (incl "/usr/vice/etc/CellAlias")
+
+(* Local Variables: *)
+(* mode: caml *)
+(* End: *)
diff --git a/Sharp.Augeas.Test/lens/aliases.aug b/Sharp.Augeas.Test/lens/aliases.aug
new file mode 100644
index 0000000..10c2d66
--- /dev/null
+++ b/Sharp.Augeas.Test/lens/aliases.aug
@@ -0,0 +1,89 @@
+(*
+Module: Aliases
+ Parses /etc/aliases
+
+Author: David Lutterkort
+
+About: Reference
+ This lens tries to keep as close as possible to `man 5 aliases` where possible.
+
+About: License
+ This file is licenced under the LGPL v2+, like the rest of Augeas.
+
+About: Lens Usage
+ See .
+
+About: Configuration files
+ This lens applies to /etc/aliases.
+
+About: Examples
+ The file contains various examples and tests.
+*)
+
+module Aliases =
+ autoload xfm
+
+ (************************************************************************
+ * Group: USEFUL PRIMITIVES
+ *************************************************************************)
+
+ (* Group: basic tokens *)
+
+ (* Variable: word *)
+ let word = /[^|", \t\n]+/
+ (* Variable: name *)
+ let name = /([^ \t\n#:|@]+|"[^"|\n]*")/ (* " make emacs calm down *)
+
+ (* Variable: command
+ * a command can contain spaces, if enclosed in double quotes, the case
+ * without spaces is taken care with
+ *)
+ let command = /(\|([^", \t\n]+|"[^"\n]+"))|("\|[^"\n]+")/
+
+ (* Group: Comments and empty lines *)
+
+ (* View: eol *)
+ let eol = Util.eol
+ (* View: comment *)
+ let comment = Util.comment
+ (* View: empty *)
+ let empty = Util.empty
+
+ (* Group: separators *)
+ (* View: colon
+ * Separation between the alias and it's destinations
+ *)
+ let colon = del /[ \t]*:[ \t]*/ ":\t"
+ (* View: comma
+ * Separation between multiple destinations
+ *)
+ let comma = del /[ \t]*,[ \t]*(\n[ \t]+)?/ ", "
+
+ (* Group: alias *)
+
+ (* View: destination
+ * Can be either a word (no spaces included) or a command with spaces
+ *)
+ let destination = ( word | command )
+
+ (* View: value_list
+ * List of destinations
+ *)
+ let value_list = Build.opt_list ([ label "value" . store destination]) comma
+
+ (* View: alias
+ * a name with one or more destinations
+ *)
+ let alias = [ seq "alias" .
+ [ label "name" . store name ] . colon .
+ value_list
+ ] . eol
+
+ (* View: lns *)
+ let lns = (comment | empty | alias)*
+
+ let xfm = transform lns (incl "/etc/aliases")
+
+(* Local Variables: *)
+(* mode: caml *)
+(* End: *)
diff --git a/Sharp.Augeas.Test/lens/anaconda.aug b/Sharp.Augeas.Test/lens/anaconda.aug
new file mode 100644
index 0000000..8f618db
--- /dev/null
+++ b/Sharp.Augeas.Test/lens/anaconda.aug
@@ -0,0 +1,30 @@
+(*
+Module: Anaconda
+ Parses Anaconda's user interaction configuration files.
+
+Author: Pino Toscano
+
+About: Reference
+ https://anaconda-installer.readthedocs.io/en/latest/user-interaction-config-file-spec.html
+
+About: Configuration file
+ This lens applies to /etc/sysconfig/anaconda.
+
+About: License
+ This file is licensed under the LGPL v2+, like the rest of Augeas.
+*)
+module Anaconda =
+autoload xfm
+
+let comment = IniFile.comment "#" "#"
+let sep = IniFile.sep "=" "="
+
+let entry = IniFile.entry IniFile.entry_re sep comment
+let title = IniFile.title IniFile.record_re
+let record = IniFile.record title entry
+
+let lns = IniFile.lns record comment
+
+let filter = incl "/etc/sysconfig/anaconda"
+
+let xfm = transform lns filter
diff --git a/Sharp.Augeas.Test/lens/anacron.aug b/Sharp.Augeas.Test/lens/anacron.aug
new file mode 100644
index 0000000..e7aa5ca
--- /dev/null
+++ b/Sharp.Augeas.Test/lens/anacron.aug
@@ -0,0 +1,87 @@
+(*
+Module: Anacron
+ Parses /etc/anacrontab
+
+Author: Raphael Pinson
+
+About: Reference
+ This lens tries to keep as close as possible to `man 5 anacrontab` where
+ possible.
+
+About: License
+ This file is licensed under the LGPL v2+, like the rest of Augeas.
+
+About: Lens Usage
+
+About: Configuration files
+ This lens applies to /etc/anacrontab. See .
+
+About: Examples
+ The file contains various examples and tests.
+*)
+
+module Anacron =
+ autoload xfm
+
+(************************************************************************
+ * Group: ENTRIES
+ *************************************************************************)
+
+
+(************************************************************************
+ * View: shellvar
+ * A shell variable in crontab
+ *************************************************************************)
+
+let shellvar = Cron.shellvar
+
+
+(* View: period *)
+let period = [ label "period" . store Rx.integer ]
+
+(* Variable: period_name_re
+ The valid values for . Currently only "monthly" *)
+let period_name_re = "monthly"
+
+(************************************************************************
+ * View: period_name
+ * In the format "@keyword"
+ *************************************************************************)
+let period_name = [ label "period_name" . Util.del_str "@"
+ . store period_name_re ]
+
+(************************************************************************
+ * View: delay
+ * The delay for an
+ *************************************************************************)
+let delay = [ label "delay" . store Rx.integer ]
+
+(************************************************************************
+ * View: job_identifier
+ * The job_identifier for an
+ *************************************************************************)
+let job_identifier = [ label "job-identifier" . store Rx.word ]
+
+(************************************************************************
+ * View: entry
+ * An anacrontab entry
+ *************************************************************************)
+
+let entry = [ label "entry" . Util.indent
+ . ( period | period_name )
+ . Sep.space . delay
+ . Sep.space . job_identifier
+ . Sep.space . store Rx.space_in . Util.eol ]
+
+
+(*
+ * View: lns
+ * The anacron lens
+ *)
+let lns = ( Util.empty | Util.comment | shellvar | entry )*
+
+
+(* Variable: filter *)
+let filter = incl "/etc/anacrontab"
+
+let xfm = transform lns filter
diff --git a/Sharp.Augeas.Test/lens/approx.aug b/Sharp.Augeas.Test/lens/approx.aug
new file mode 100644
index 0000000..a482d1a
--- /dev/null
+++ b/Sharp.Augeas.Test/lens/approx.aug
@@ -0,0 +1,59 @@
+(*
+Module: Approx
+ Parses /etc/approx/approx.conf
+
+Author: David Lutterkort
+
+About: Reference
+ This lens tries to keep as close as possible to `man 5 approx.conf` where possible.
+
+About: License
+ This file is licenced under the LGPL v2+, like the rest of Augeas.
+
+About: Lens Usage
+ See .
+
+About: Configuration files
+ This lens applies to /etc/approx/approx.conf.
+
+About: Examples
+ The file contains various examples and tests.
+*)
+
+module Approx =
+ autoload xfm
+
+ (* Variable: eol
+ An *)
+ let eol = Util.eol
+
+ (* Variable: indent
+ An *)
+ let indent = Util.indent
+
+ (* Variable: key_re *)
+ let key_re = /\$?[A-Za-z0-9_.-]+/
+
+ (* Variable: sep *)
+ let sep = /[ \t]+/
+
+ (* Variable: value_re *)
+ let value_re = /[^ \t\n](.*[^ \t\n])?/
+
+ (* View: comment *)
+ let comment = [ indent . label "#comment" . del /[#;][ \t]*/ "# "
+ . store /([^ \t\n].*[^ \t\n]|[^ \t\n])/ . eol ]
+
+ (* View: empty
+ An *)
+ let empty = Util.empty
+
+ (* View: kv *)
+ let kv = [ indent . key key_re . del sep " " . store value_re . eol ]
+
+ (* View: lns *)
+ let lns = (empty | comment | kv) *
+
+ (* View: filter *)
+ let filter = incl "/etc/approx/approx.conf"
+ let xfm = transform lns filter
diff --git a/Sharp.Augeas.Test/lens/apt_update_manager.aug b/Sharp.Augeas.Test/lens/apt_update_manager.aug
new file mode 100644
index 0000000..f1c361d
--- /dev/null
+++ b/Sharp.Augeas.Test/lens/apt_update_manager.aug
@@ -0,0 +1,47 @@
+(*
+Module: Apt_Update_Manager
+ Parses files in /etc/update-manager
+
+Author: Raphael Pinson
+
+About: License
+ This file is licenced under the LGPL v2+, like the rest of Augeas.
+
+About: Lens Usage
+ To be documented
+
+About: Configuration files
+ This lens applies to files in /etc/update-manager. See .
+
+About: Examples
+ The file contains various examples and tests.
+*)
+module Apt_Update_Manager =
+
+autoload xfm
+
+(* View: comment *)
+let comment = IniFile.comment IniFile.comment_re IniFile.comment_default
+
+(* View: sep *)
+let sep = IniFile.sep IniFile.sep_re IniFile.sep_default
+
+(* View: title *)
+let title = IniFile.title Rx.word
+
+(* View: entry *)
+let entry = IniFile.entry Rx.word sep comment
+
+(* View: record *)
+let record = IniFile.record title entry
+
+(* View: lns *)
+let lns = IniFile.lns record comment
+
+(* Variable: filter *)
+let filter = incl "/etc/update-manager/meta-release"
+ . incl "/etc/update-manager/release-upgrades"
+ . incl "/etc/update-manager/release-upgrades.d/*"
+ . Util.stdexcl
+
+let xfm = transform lns filter
diff --git a/Sharp.Augeas.Test/lens/aptcacherngsecurity.aug b/Sharp.Augeas.Test/lens/aptcacherngsecurity.aug
new file mode 100644
index 0000000..204ea5b
--- /dev/null
+++ b/Sharp.Augeas.Test/lens/aptcacherngsecurity.aug
@@ -0,0 +1,25 @@
+(* Module: AptCacherNGSecurity
+
+ Lens for config files like the one found in
+ /etc/apt-cacher-ng/security.conf
+
+
+ About: License
+ Copyright 2013 Erik B. Andersen; this file is licenced under the LGPL v2+.
+*)
+module AptCacherNGSecurity =
+ autoload xfm
+
+ (* Define a Username/PW pair *)
+ let authpair = [ key /[^ \t:\/]*/ . del /:/ ":" . store /[^: \t\n]*/ ]
+
+ (* Define a record. So far as I can tell, the only auth level supported is Admin *)
+ let record = [ key "AdminAuth". del /[ \t]*:[ \t]*/ ": ". authpair . Util.del_str "\n"]
+
+ (* Define the basic lens *)
+ let lns = ( record | Util.empty | Util.comment )*
+
+ let filter = incl "/etc/apt-cacher-ng/security.conf"
+ . Util.stdexcl
+
+ let xfm = transform lns filter
diff --git a/Sharp.Augeas.Test/lens/aptconf.aug b/Sharp.Augeas.Test/lens/aptconf.aug
new file mode 100644
index 0000000..2131540
--- /dev/null
+++ b/Sharp.Augeas.Test/lens/aptconf.aug
@@ -0,0 +1,151 @@
+(*
+Module: AptConf
+ Parses /etc/apt/apt.conf and /etc/apt/apt.conf.d/*
+
+Author: Raphael Pinson
+
+About: Reference
+ This lens tries to keep as close as possible to `man 5 apt.conf`
+where possible.
+
+About: License
+ This file is licenced under the LGPL v2+, like the rest of Augeas.
+
+About: Lens Usage
+ To be documented
+
+About: Configuration files
+ This lens applies to /etc/apt/apt.conf and /etc/apt/apt.conf.d/*.
+See .
+*)
+
+
+module AptConf =
+ autoload xfm
+
+(************************************************************************
+ * Group: USEFUL PRIMITIVES
+ *************************************************************************)
+
+(* View: eol
+ And end of line *)
+let eol = Util.eol
+
+(* View: empty
+ A C-style empty line *)
+let empty = Util.empty_any
+
+(* View: indent
+ An indentation *)
+let indent = Util.indent
+
+(* View: comment_simple
+ A one-line comment, C-style *)
+let comment_simple = Util.comment_c_style_or_hash
+
+(* View: comment_multi
+ A multiline comment, C-style *)
+let comment_multi = Util.comment_multiline
+
+(* View: comment
+ A comment, either or *)
+let comment = comment_simple | comment_multi
+
+
+(************************************************************************
+ * Group: ENTRIES
+ *************************************************************************)
+
+(* View: name_re
+ Regex for entry names *)
+let name_re = /[A-Za-z][A-Za-z-]*/
+
+(* View: name_re_colons
+ Regex for entry names with colons *)
+let name_re_colons = /[A-Za-z][A-Za-z:-]*/
+
+
+(* View: entry
+ An apt.conf entry, recursive
+
+ WARNING:
+ This lens exploits a put ambiguity
+ since apt.conf allows for both
+ APT { Clean-Installed { "true" } }
+ and APT::Clean-Installed "true";
+ but we're choosing to map them the same way
+
+ The recursive lens doesn't seem
+ to care and defaults to the first
+ item in the union.
+
+ This is why the APT { Clean-Installed { "true"; } }
+ form is listed first, since it supports
+ all subnodes (which Dpkg::Conf) doesn't.
+
+ Exchanging these two expressions in the union
+ makes tests fails since the tree cannot
+ be mapped back.
+
+ This situation results in existing
+ configuration being modified when the
+ associated tree is modified. For example,
+ changing the value of
+ APT::Clean-Installed "true"; to "false"
+ results in
+ APT { Clean-Installed "false"; }
+ (see unit tests)
+ *)
+let rec entry_noeol =
+ let value =
+ Util.del_str "\"" . store /[^"\n]+/
+ . del /";?/ "\";" in
+ let opt_eol = del /[ \t\n]*/ "\n" in
+ let long_eol = del /[ \t]*\n+/ "\n" in
+ let list_elem = [ opt_eol . label "@elem" . value ] in
+ let eol_comment = del /([ \t\n]*\n)?/ "" . comment in
+ [ key name_re . Sep.space . value ]
+ | [ key name_re . del /[ \t\n]*\{/ " {" .
+ ( (opt_eol . entry_noeol) |
+ list_elem |
+ eol_comment
+ )* .
+ del /[ \t\n]*\};?/ "\n};" ]
+ | [ key name_re . Util.del_str "::" . entry_noeol ]
+
+let entry = indent . entry_noeol . eol
+
+
+(* View: include
+ A file inclusion
+ /!\ The manpage is not clear on the syntax *)
+let include =
+ [ indent . key "#include" . Sep.space
+ . store Rx.fspath . eol ]
+
+
+(* View: clear
+ A list of variables to clear
+ /!\ The manpage is not clear on the syntax *)
+let clear =
+ let name = [ label "name" . store name_re_colons ] in
+ [ indent . key "#clear" . Sep.space
+ . Build.opt_list name Sep.space
+ . eol ]
+
+
+(************************************************************************
+ * Group: LENS AND FILTER
+ *************************************************************************)
+
+(* View: lns
+ The apt.conf lens *)
+let lns = (empty|comment|entry|include|clear)*
+
+
+(* View: filter *)
+let filter = incl "/etc/apt/apt.conf"
+ . incl "/etc/apt/apt.conf.d/*"
+ . Util.stdexcl
+
+let xfm = transform lns filter
diff --git a/Sharp.Augeas.Test/lens/aptpreferences.aug b/Sharp.Augeas.Test/lens/aptpreferences.aug
new file mode 100644
index 0000000..0c3c84c
--- /dev/null
+++ b/Sharp.Augeas.Test/lens/aptpreferences.aug
@@ -0,0 +1,69 @@
+(*
+Module: AptPreferences
+ Apt/preferences module for Augeas
+
+Author: Raphael Pinson
+*)
+
+module AptPreferences =
+autoload xfm
+
+(************************************************************************
+ * Group: Entries
+ ************************************************************************)
+
+(* View: colon *)
+let colon = del /:[ \t]*/ ": "
+
+(* View: pin_gen
+ A generic pin
+
+ Parameters:
+ lbl:string - the label *)
+let pin_gen (lbl:string) = store lbl
+ . [ label lbl . Sep.space . store Rx.no_spaces ]
+
+(* View: pin_keys *)
+let pin_keys =
+ let space_in = store /[^, \r\t\n][^,\n]*[^, \r\t\n]|[^, \t\n\r]/
+ in Build.key_value /[aclnov]/ Sep.equal space_in
+
+(* View: pin_options *)
+let pin_options =
+ let comma = Util.delim ","
+ in store "release" . Sep.space
+ . Build.opt_list pin_keys comma
+
+(* View: version_pin *)
+let version_pin = pin_gen "version"
+
+(* View: origin_pin *)
+let origin_pin = pin_gen "origin"
+
+(* View: pin *)
+let pin =
+ let pin_value = pin_options | version_pin | origin_pin
+ in Build.key_value_line "Pin" colon pin_value
+
+(* View: entries *)
+let entries = Build.key_value_line ("Explanation"|"Package"|"Pin-Priority")
+ colon (store Rx.space_in)
+ | pin
+ | Util.comment
+
+(* View: record *)
+let record = [ seq "record" . entries+ ]
+
+(************************************************************************
+ * Group: Lens
+ ************************************************************************)
+
+(* View: lns *)
+let lns = Util.empty* . (Build.opt_list record Util.eol+ . Util.empty*)?
+
+(* View: filter *)
+let filter = incl "/etc/apt/preferences"
+ . incl "/etc/apt/preferences.d/*"
+ . Util.stdexcl
+
+let xfm = transform lns filter
diff --git a/Sharp.Augeas.Test/lens/aptsources.aug b/Sharp.Augeas.Test/lens/aptsources.aug
new file mode 100644
index 0000000..d7a6b3b
--- /dev/null
+++ b/Sharp.Augeas.Test/lens/aptsources.aug
@@ -0,0 +1,70 @@
+(*
+Module: Aptsources
+ Parsing /etc/apt/sources.list
+*)
+
+module Aptsources =
+ autoload xfm
+
+(************************************************************************
+ * Group: Utility variables/functions
+ ************************************************************************)
+ (* View: sep_ws *)
+ let sep_ws = Sep.space
+
+ (* View: eol *)
+ let eol = Util.del_str "\n"
+
+ (* View: comment *)
+ let comment = Util.comment
+ (* View: empty *)
+ let empty = Util.empty
+
+ (* View: word *)
+ let word = /[^][# \n\t]+/
+
+ (* View: uri *)
+ let uri =
+ let protocol = /[a-z+]+:/
+ in let path = /\/[^] \t]*/
+ in let path_brack = /\[[^]]+\]\/?/
+ in protocol? . path
+ | protocol . path_brack
+
+(************************************************************************
+ * Group: Keywords
+ ************************************************************************)
+ (* View: record *)
+ let record =
+ let option_sep = [ label "operation" . store /[+-]/]? . Sep.equal
+ in let option = Build.key_value /arch|trusted/ option_sep (store Rx.word)
+ in let options = [ label "options"
+ . Util.del_str "[" . Sep.opt_space
+ . Build.opt_list option Sep.space
+ . Sep.opt_space . Util.del_str "]"
+ . sep_ws ]
+ in [ Util.indent . seq "source"
+ . [ label "type" . store word ] . sep_ws
+ . options?
+ . [ label "uri" . store uri ] . sep_ws
+ . [ label "distribution" . store word ]
+ . [ label "component" . sep_ws . store word ]*
+ . del /[ \t]*(#.*)?/ ""
+ . eol ]
+
+(************************************************************************
+ * Group: Lens
+ ************************************************************************)
+ (* View: lns *)
+ let lns = ( comment | empty | record ) *
+
+ (* View: filter *)
+ let filter = (incl "/etc/apt/sources.list")
+ . (incl "/etc/apt/sources.list.d/*")
+ . Util.stdexcl
+
+ let xfm = transform lns filter
+
+(* Local Variables: *)
+(* mode: caml *)
+(* End: *)
diff --git a/Sharp.Augeas.Test/lens/authinfo2.aug b/Sharp.Augeas.Test/lens/authinfo2.aug
new file mode 100644
index 0000000..7ef4ba2
--- /dev/null
+++ b/Sharp.Augeas.Test/lens/authinfo2.aug
@@ -0,0 +1,39 @@
+(* Authinfo2 module for Augeas *)
+(* Author: Nicolas Gif *)
+(* Heavily based on DPUT module by Raphael Pinson *)
+(* *)
+(* *)
+
+module Authinfo2 =
+ autoload xfm
+
+(************************************************************************
+ * INI File settings
+ *************************************************************************)
+let comment = IniFile.comment IniFile.comment_re "#"
+
+let sep = IniFile.sep IniFile.sep_re ":"
+
+
+(************************************************************************
+ * ENTRY
+ *************************************************************************)
+let entry =
+ IniFile.entry_generic_nocomment (key IniFile.entry_re) sep IniFile.comment_re comment
+
+
+(************************************************************************
+ * TITLE & RECORD
+ *************************************************************************)
+let title = IniFile.title IniFile.record_re
+let record = IniFile.record title entry
+
+
+(************************************************************************
+ * LENS & FILTER
+ *************************************************************************)
+let lns = IniFile.lns record comment
+
+let filter = (incl (Sys.getenv("HOME") . "/.s3ql/authinfo2"))
+
+let xfm = transform lns filter
diff --git a/Sharp.Augeas.Test/lens/authorized_keys.aug b/Sharp.Augeas.Test/lens/authorized_keys.aug
new file mode 100644
index 0000000..e913d4b
--- /dev/null
+++ b/Sharp.Augeas.Test/lens/authorized_keys.aug
@@ -0,0 +1,72 @@
+(*
+Module: Authorized_Keys
+ Parses SSH authorized_keys
+
+Author: Raphael Pinson
+
+About: Reference
+ This lens tries to keep as close as possible to `man 5 authorized_keys` where possible.
+
+About: License
+ This file is licenced under the LGPL v2+, like the rest of Augeas.
+
+About: Lens Usage
+ To be documented
+
+About: Configuration files
+ This lens applies to SSH authorized_keys. See .
+
+About: Examples
+ The file contains various examples and tests.
+*)
+
+
+module Authorized_Keys =
+
+autoload xfm
+
+(* View: option
+ A key option *)
+let option =
+ let kv_re = "command" | "environment" | "from"
+ | "permitopen" | "principals" | "tunnel"
+ in let flag_re = "cert-authority" | "no-agent-forwarding"
+ | "no-port-forwarding" | "no-pty" | "no-user-rc"
+ | "no-X11-forwarding"
+ in let option_value = Util.del_str "\""
+ . store /((\\\\")?[^\\\n"]*)+/
+ . Util.del_str "\""
+ in Build.key_value kv_re Sep.equal option_value
+ | Build.flag flag_re
+
+(* View: key_options
+ A list of key