/// <summary> /// Reads the specification file that specifies the contents of the package. /// </summary> /// <param name="fileName">The name of the package specification file.</param> public void ReadSpecification(string fileName) { srcBasePath = Path.GetDirectoryName(fileName); controlParams = new DebControlParams(); using (var sr = new StreamReader(fileName)) { int lineNumber = 0; bool inDescription = false; while (!sr.EndOfStream) { string line = sr.ReadLine(); lineNumber++; Match m; if (line.TrimStart() == "") { inDescription = false; continue; // Skip empty lines } if (line.TrimStart().StartsWith("#")) { inDescription = false; continue; // Skip comments } m = Regex.Match(line, @"^basepath\s*:\s*(.+)$", RegexOptions.IgnoreCase); if (m.Success) { srcBasePath = ResolveVariables(m.Groups[1].Value.Trim()); if (!Path.IsPathRooted(srcBasePath)) { // Interpret non-rooted paths relative to the spec file srcBasePath = Path.Combine(Path.GetDirectoryName(fileName), srcBasePath); } if (!Directory.Exists(srcBasePath)) { throw new ArgumentException("Specified base path directory does not exist: " + srcBasePath); } inDescription = false; continue; } m = Regex.Match(line, @"^outdir\s*:\s*(.+)$", RegexOptions.IgnoreCase); if (m.Success) { OutDir = ResolveVariables(m.Groups[1].Value.Trim()); if (!Path.IsPathRooted(OutDir)) { // Interpret non-rooted paths relative to the spec file OutDir = Path.Combine(Path.GetDirectoryName(fileName), OutDir); } inDescription = false; continue; } m = Regex.Match(line, @"^package\s*:\s*(.+)$", RegexOptions.IgnoreCase); if (m.Success) { controlParams.Package = ResolveVariables(m.Groups[1].Value.Trim()); // Source: https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Source if (!Regex.IsMatch(controlParams.Package, "^[a-z0-9+.-]+$")) { throw new FormatException("Invalid format of the Package name."); } inDescription = false; continue; } m = Regex.Match(line, @"^version\s*:\s*(.+)$", RegexOptions.IgnoreCase); if (m.Success) { controlParams.Version = ResolveVariables(m.Groups[1].Value.Trim()); // Source: https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version if (!Regex.IsMatch(controlParams.Version, "^[A-Za-z0-9.+~-]+$")) { throw new FormatException("Invalid format of the Version number."); } inDescription = false; continue; } m = Regex.Match(line, @"^convert-semver\s*$", RegexOptions.IgnoreCase); if (m.Success) { controlParams.ConvertFromSemVer = true; inDescription = false; continue; } m = Regex.Match(line, @"^section\s*:\s*(.+)$", RegexOptions.IgnoreCase); if (m.Success) { controlParams.Section = ResolveVariables(m.Groups[1].Value.Trim()); inDescription = false; continue; } m = Regex.Match(line, @"^prio(?:rity)?\s*:\s*(.+)$", RegexOptions.IgnoreCase); if (m.Success) { controlParams.Priority = ResolveVariables(m.Groups[1].Value.Trim()); inDescription = false; continue; } m = Regex.Match(line, @"^arch(?:itecture)?\s*:\s*(.+)$", RegexOptions.IgnoreCase); if (m.Success) { controlParams.Architecture = ResolveVariables(m.Groups[1].Value.Trim()); inDescription = false; continue; } m = Regex.Match(line, @"^depends\s*:\s*(.+)$", RegexOptions.IgnoreCase); if (m.Success) { string depends = ResolveVariables(m.Groups[1].Value.Trim()); inDescription = false; if (string.IsNullOrWhiteSpace(controlParams.Depends)) { controlParams.Depends = depends; } else { controlParams.Depends += ", " + depends; } continue; } m = Regex.Match(line, @"^pre-depends\s*:\s*(.+)$", RegexOptions.IgnoreCase); if (m.Success) { string preDepends = ResolveVariables(m.Groups[1].Value.Trim()); inDescription = false; if (string.IsNullOrWhiteSpace(controlParams.PreDepends)) { controlParams.PreDepends = preDepends; } else { controlParams.PreDepends += ", " + preDepends; } continue; } m = Regex.Match(line, @"^conflicts\s*:\s*(.+)$", RegexOptions.IgnoreCase); if (m.Success) { controlParams.Conflicts = ResolveVariables(m.Groups[1].Value.Trim()); inDescription = false; continue; } m = Regex.Match(line, @"^maintainer\s*:\s*(.+)$", RegexOptions.IgnoreCase); if (m.Success) { controlParams.Maintainer = ResolveVariables(m.Groups[1].Value.Trim()); inDescription = false; continue; } m = Regex.Match(line, @"^homepage\s*:\s*(.+)$", RegexOptions.IgnoreCase); if (m.Success) { controlParams.Homepage = ResolveVariables(m.Groups[1].Value.Trim()); inDescription = false; continue; } m = Regex.Match(line, @"^desc(?:ription)?\s*:\s*(.+)$", RegexOptions.IgnoreCase); if (m.Success) { controlParams.Description = ResolveVariables(m.Groups[1].Value.Trim()); inDescription = true; continue; } m = Regex.Match(line, @"^preinst\s*:\s*(.+)$", RegexOptions.IgnoreCase); if (m.Success) { preInstFileName = ResolveVariables(m.Groups[1].Value.Trim()); if (!Path.IsPathRooted(preInstFileName)) { // Interpret non-rooted paths relative to the base path preInstFileName = Path.Combine(srcBasePath, preInstFileName); } inDescription = false; continue; } m = Regex.Match(line, @"^postinst\s*:\s*(.+)$", RegexOptions.IgnoreCase); if (m.Success) { postInstFileName = ResolveVariables(m.Groups[1].Value.Trim()); if (!Path.IsPathRooted(postInstFileName)) { // Interpret non-rooted paths relative to the base path postInstFileName = Path.Combine(srcBasePath, postInstFileName); } inDescription = false; continue; } m = Regex.Match(line, @"^prerm\s*:\s*(.+)$", RegexOptions.IgnoreCase); if (m.Success) { preRmFileName = ResolveVariables(m.Groups[1].Value.Trim()); if (!Path.IsPathRooted(preRmFileName)) { // Interpret non-rooted paths relative to the base path preRmFileName = Path.Combine(srcBasePath, preRmFileName); } inDescription = false; continue; } m = Regex.Match(line, @"^postrm\s*:\s*(.+)$", RegexOptions.IgnoreCase); if (m.Success) { postRmFileName = ResolveVariables(m.Groups[1].Value.Trim()); if (!Path.IsPathRooted(postRmFileName)) { // Interpret non-rooted paths relative to the base path postRmFileName = Path.Combine(srcBasePath, postRmFileName); } inDescription = false; continue; } m = Regex.Match(line, @"^file\s*:\s*(\S+)\s+(\S+)(?:\s+([0-9]+)(?:\s+([0-9]+)\s+([0-9]+))?)?\s*$", RegexOptions.IgnoreCase); if (m.Success) { // Add data file var fileItem = new DebFileItem { SourcePath = ResolveVariables(m.Groups[1].Value.Trim()) }; if (!Path.IsPathRooted(fileItem.SourcePath)) { // Interpret non-rooted paths relative to the base path fileItem.SourcePath = Path.Combine(srcBasePath, fileItem.SourcePath); } fileItem.DestPath = ResolveVariables(m.Groups[2].Value.Trim()); if (m.Groups[3].Length > 0) { fileItem.Mode = Convert.ToInt32(ResolveVariables(m.Groups[3].Value), 8); } if (m.Groups[4].Length > 0) { fileItem.UserId = Convert.ToInt32(ResolveVariables(m.Groups[4].Value)); } if (m.Groups[5].Length > 0) { fileItem.GroupId = Convert.ToInt32(ResolveVariables(m.Groups[5].Value)); } foreach (var fi in ResolveFileItems(fileItem)) { var existingItem = fileItems.FirstOrDefault(x => x.SourcePath == fi.SourcePath); if (existingItem != null) { fileItems.Remove(existingItem); } fileItems.Add(fi); } inDescription = false; continue; } m = Regex.Match(line, @"^conffile\s*:\s*(\S+)\s+(\S+)(?:\s+([0-9]+)(?:\s+([0-9]+)\s+([0-9]+))?)?\s*$", RegexOptions.IgnoreCase); if (m.Success) { // Add data file as conffile var fileItem = new DebFileItem { SourcePath = ResolveVariables(m.Groups[1].Value.Trim()) }; if (!Path.IsPathRooted(fileItem.SourcePath)) { // Interpret non-rooted paths relative to the base path fileItem.SourcePath = Path.Combine(srcBasePath, fileItem.SourcePath); } fileItem.DestPath = ResolveVariables(m.Groups[2].Value.Trim()); if (m.Groups[3].Length > 0) { fileItem.Mode = Convert.ToInt32(ResolveVariables(m.Groups[3].Value), 8); } if (m.Groups[4].Length > 0) { fileItem.UserId = Convert.ToInt32(ResolveVariables(m.Groups[4].Value)); } if (m.Groups[5].Length > 0) { fileItem.GroupId = Convert.ToInt32(ResolveVariables(m.Groups[5].Value)); } fileItem.IsConfig = true; foreach (var fi in ResolveFileItems(fileItem)) { fileItems.Add(fi); } inDescription = false; continue; } m = Regex.Match(line, @"^dir(?:ectory)?\s*:\s*(\S+)(?:\s+([0-9]+)(?:\s+([0-9]+)\s+([0-9]+))?)?\s*$", RegexOptions.IgnoreCase); if (m.Success) { // Add empty directory var fileItem = new DebFileItem { DestPath = ResolveVariables(m.Groups[1].Value.Trim()).TrimEnd('/') }; if (m.Groups[2].Length > 0) { fileItem.Mode = Convert.ToInt32(ResolveVariables(m.Groups[2].Value), 8); } else { fileItem.Mode = 493 /* 0755 */; } if (m.Groups[3].Length > 0) { fileItem.UserId = Convert.ToInt32(ResolveVariables(m.Groups[3].Value)); } if (m.Groups[4].Length > 0) { fileItem.GroupId = Convert.ToInt32(ResolveVariables(m.Groups[4].Value)); } fileItem.IsDirectory = true; fileItems.Add(fileItem); inDescription = false; continue; } m = Regex.Match(line, @"^(\S+)\s*=\s*(.+)$", RegexOptions.IgnoreCase); if (m.Success) { variables[m.Groups[1].Value.Trim()] = ResolveVariables(m.Groups[2].Value.Trim()); inDescription = false; continue; } if (inDescription) { m = Regex.Match(line, @"^\s+", RegexOptions.IgnoreCase); if (m.Success) { // Continuation line for the Description field, follows the original control file syntax controlParams.Description += "\n" + ResolveVariables(line.TrimEnd()); continue; } } throw new Exception("Unrecognised directive in line " + lineNumber + "."); } } if (string.IsNullOrWhiteSpace(controlParams.Package)) { throw new ArgumentException("Package field missing."); } if (string.IsNullOrWhiteSpace(controlParams.Version)) { throw new ArgumentException("Version field missing."); } if (string.IsNullOrWhiteSpace(controlParams.Architecture)) { throw new ArgumentException("Architecture field missing."); } if (string.IsNullOrWhiteSpace(controlParams.Maintainer)) { throw new ArgumentException("Maintainer field missing."); } if (string.IsNullOrWhiteSpace(controlParams.Description)) { throw new ArgumentException("Description field missing."); } // Calculate InstalledSize in KiB // Source: https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Installed-Size long byteCount = 0; foreach (var fileItem in fileItems) { if (fileItem.SourcePath != null) { var fi = new FileInfo(fileItem.SourcePath); byteCount += fi.Length; } } controlParams.InstalledSize = (long)Math.Ceiling((decimal)byteCount / 1024); }
public void ReadSpecificationDeb(string path) { srcBasePath = Path.GetDirectoryName(path); controlParams = new DebControlParams(); var confDir = Path.Combine(path, "DEBIAN"); #region get control file check var controlFile = File.ReadAllText(Path.Combine(confDir, "control")); var m = Regex.Match(controlFile, @"package\s*:\s*(.+)", RegexOptions.IgnoreCase); if (m.Success) { controlParams.Package = ResolveVariables(m.Groups[1].Value.Trim()); } m = Regex.Match(controlFile, @"version\s*:\s*(.+)", RegexOptions.IgnoreCase); if (m.Success) { controlParams.Version = ResolveVariables(m.Groups[1].Value.Trim()); } m = Regex.Match(controlFile, @"convert-semver\s*", RegexOptions.IgnoreCase); if (m.Success) { controlParams.ConvertFromSemVer = true; } m = Regex.Match(controlFile, @"section\s*:\s*(.+)", RegexOptions.IgnoreCase); if (m.Success) { controlParams.Section = ResolveVariables(m.Groups[1].Value.Trim()); } m = Regex.Match(controlFile, @"prio(?:rity)?\s*:\s*(.+)", RegexOptions.IgnoreCase); if (m.Success) { controlParams.Priority = ResolveVariables(m.Groups[1].Value.Trim()); } m = Regex.Match(controlFile, @"arch(?:itecture)?\s*:\s*(.+)", RegexOptions.IgnoreCase); if (m.Success) { controlParams.Architecture = ResolveVariables(m.Groups[1].Value.Trim()); } m = Regex.Match(controlFile, @"depends\s*:\s*(.+)", RegexOptions.IgnoreCase); if (m.Success) { string depends = ResolveVariables(m.Groups[1].Value.Trim()); if (string.IsNullOrWhiteSpace(controlParams.Depends)) { controlParams.Depends = depends; } else { controlParams.Depends += ", " + depends; } } m = Regex.Match(controlFile, @"pre-depends\s*:\s*(.+)", RegexOptions.IgnoreCase); if (m.Success) { string preDepends = ResolveVariables(m.Groups[1].Value.Trim()); if (string.IsNullOrWhiteSpace(controlParams.PreDepends)) { controlParams.PreDepends = preDepends; } else { controlParams.PreDepends += ", " + preDepends; } } m = Regex.Match(controlFile, @"conflicts\s*:\s*(.+)", RegexOptions.IgnoreCase); if (m.Success) { controlParams.Conflicts = ResolveVariables(m.Groups[1].Value.Trim()); } m = Regex.Match(controlFile, @"maintainer\s*:\s*(.+)", RegexOptions.IgnoreCase); if (m.Success) { controlParams.Maintainer = ResolveVariables(m.Groups[1].Value.Trim()); } m = Regex.Match(controlFile, @"homepage\s*:\s*(.+)", RegexOptions.IgnoreCase); if (m.Success) { controlParams.Homepage = ResolveVariables(m.Groups[1].Value.Trim()); } m = Regex.Match(controlFile, @"desc(?:ription)?\s*:\s*(.+)", RegexOptions.IgnoreCase); if (m.Success) { controlParams.Description = ResolveVariables(m.Groups[1].Value.Trim()); } #endregion // preinst if (File.Exists(Path.Combine(confDir, "preinst"))) { preInstFileName = Path.Combine(confDir, "preinst"); } // postinst if (File.Exists(Path.Combine(confDir, "postinst"))) { postInstFileName = Path.Combine(confDir, "postinst"); } // prerm if (File.Exists(Path.Combine(confDir, "prerm"))) { preRmFileName = Path.Combine(confDir, "prerm"); } // postrm if (File.Exists(Path.Combine(confDir, "postrm"))) { postRmFileName = Path.Combine(confDir, "postrm"); } #region add files // Add data file foreach (var file in Directory.GetFiles(path, "*", SearchOption.AllDirectories)) { var destPath = file.Replace(path, "").TrimStart('\\'); if (destPath.StartsWith("DEBIAN")) { continue; } var fileItem = new DebFileItem { SourcePath = file }; fileItem.DestPath = destPath.Replace(@"\", "/"); //fileItem.Mode = Convert.ToInt32(ResolveVariables(m.Groups[3].Value), 8); //fileItem.UserId = Convert.ToInt32(ResolveVariables(m.Groups[4].Value)); //fileItem.GroupId = Convert.ToInt32(ResolveVariables(m.Groups[5].Value)); foreach (var fi in ResolveFileItems(fileItem)) { var existingItem = fileItems.FirstOrDefault(x => x.SourcePath == fi.SourcePath); if (existingItem != null) { fileItems.Remove(existingItem); } fileItems.Add(fi); } } #endregion #region add empty dir foreach (var dir in Directory.GetDirectories(path, "*", SearchOption.AllDirectories)) { var destPath = dir.Replace(path, "").TrimStart('\\'); if (destPath.StartsWith("DEBIAN")) { continue; } var fileItem = new DebFileItem { DestPath = destPath.Replace(@"\", "/") }; fileItem.Mode = 493 /* 0755 */; //fileItem.UserId = Convert.ToInt32(ResolveVariables(m.Groups[3].Value)); //fileItem.GroupId = Convert.ToInt32(ResolveVariables(m.Groups[4].Value)); fileItem.IsDirectory = true; fileItems.Add(fileItem); } #endregion if (string.IsNullOrWhiteSpace(controlParams.Package)) { throw new ArgumentException("Package field missing."); } if (string.IsNullOrWhiteSpace(controlParams.Version)) { throw new ArgumentException("Version field missing."); } if (string.IsNullOrWhiteSpace(controlParams.Architecture)) { throw new ArgumentException("Architecture field missing."); } if (string.IsNullOrWhiteSpace(controlParams.Maintainer)) { throw new ArgumentException("Maintainer field missing."); } if (string.IsNullOrWhiteSpace(controlParams.Description)) { throw new ArgumentException("Description field missing."); } // Calculate InstalledSize in KiB // Source: https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Installed-Size long byteCount = 0; foreach (var fileItem in fileItems) { if (fileItem.SourcePath != null) { var fi = new FileInfo(fileItem.SourcePath); byteCount += fi.Length; } } controlParams.InstalledSize = (long)Math.Ceiling((decimal)byteCount / 1024); }