src/main/java/cz/frantovo/rozsireneatributy/CLIParser.java
author František Kučera <franta-hg@frantovo.cz>
Sun, 24 Dec 2023 00:38:41 +0100
branchv_0
changeset 42 d2414701ce09
parent 39 ec0e970e0830
permissions -rw-r--r--
režimy zamykání:

- vypnuté: tlačítko pro zamykání je skryté a soubor se nezamyká
- volitelné: uživatel může soubor zamknout, ale může editovat i bez toho
- povinné: uživatel musí soubor zamknout, aby mohl atributy editovat

Změny v atributech se vždy propisují okamžitě - na ně zámek nemá vliv.
Zámek je na souboru (ne metadatech) a slouží pro kooperující procesy.
Proces, který soubor/metadata čte, si jednak může soubor zamknout (POSIX)
a tím mít jistotu, že zrovna neprobíhá editace.
A jednak může reagovat na notifikace CLOSE_WRITE (inotify).
Notifikaci mu pošleme tím, že soubor odemkneme (čímž se i zavře).
     1 /**
     2  * Rozšířené atributy – program na správu rozšířených atributů souborů
     3  * Copyright © 2023 František Kučera (frantovo.cz)
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, either version 3 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16  */
    17 package cz.frantovo.rozsireneatributy;
    18 
    19 import cz.frantovo.rozsireneatributy.Konfigurace.DefiniceAtributu;
    20 import cz.frantovo.rozsireneatributy.Konfigurace.DefiniceHodnoty;
    21 import cz.frantovo.rozsireneatributy.Konfigurace.RežimZamykání;
    22 import java.io.File;
    23 import java.util.Arrays;
    24 import java.util.Collection;
    25 import java.util.ResourceBundle;
    26 
    27 /**
    28  * Converts command line arguments from String array to object. Checks basic
    29  * constraints (if only supported options are used and if they have correct
    30  * number of parameters)
    31  *
    32  * @author Ing. František Kučera (frantovo.cz)
    33  */
    34 public class CLIParser {
    35 
    36 	private static final ResourceBundle překlady = ResourceBundle
    37 		.getBundle(Atribut.class.getPackageName() + ".Překlady");
    38 
    39 	public Konfigurace parsujParametry(String[] parametry)
    40 		throws CLIParserException {
    41 		Konfigurace k = new Konfigurace();
    42 
    43 		for (int i = 0; i < parametry.length; i++) {
    44 			String parametr = parametry[i];
    45 
    46 			boolean odpovídá = false;
    47 
    48 			for (Token t : Token.values()) {
    49 				if (t.odpovídá(parametr)) {
    50 					int parsedArgs = t.parsuj(parametry, i, k);
    51 					i = i + parsedArgs;
    52 					odpovídá = true;
    53 				}
    54 			}
    55 
    56 			if (!odpovídá) {
    57 				throw new CLIParserException(
    58 					překlady.getString("chyba.cli.neznámýParametr") + parametr);
    59 			}
    60 		}
    61 
    62 		if (k.getSoubor() == null)
    63 			throw new CLIParserException(
    64 				překlady.getString("chyba.cli.chybíSoubor"));
    65 
    66 		return k;
    67 	}
    68 
    69 	private static String načtiDalší(String[] parametry, int index)
    70 		throws CLIParserException {
    71 		if (index < parametry.length) {
    72 			return parametry[index];
    73 		} else {
    74 			throw new CLIParserException("Expecting value for option: "
    75 				+ parametry[index - 1]);
    76 		}
    77 	}
    78 
    79 	private static boolean načtiDalšíBoolean(String[] parametry, int index)
    80 		throws CLIParserException {
    81 		String s = načtiDalší(parametry, index);
    82 		switch (s) {
    83 			case "true":
    84 			case "ano":
    85 				return true;
    86 			case "false":
    87 			case "ne":
    88 				return false;
    89 			default:
    90 				throw new CLIParserException("Neplatná logická hodnota: " + s);
    91 		}
    92 	}
    93 
    94 	private static enum Token {
    95 
    96 		SOUBOR("--soubor", "--file") {
    97 			@Override
    98 			public int parsuj(String[] parametry, int index, Konfigurace k)
    99 				throws CLIParserException {
   100 				int originalIndex = index;
   101 				k.setSoubor(new File(načtiDalší(parametry, ++index)));
   102 				return index - originalIndex;
   103 			}
   104 		},
   105 		REŽIM_ZAMYKÁNÍ("--režim-zamykání", "--locking-mode") {
   106 			@Override
   107 			public int parsuj(String[] parametry, int index, Konfigurace k)
   108 				throws CLIParserException {
   109 				int originalIndex = index;
   110 				String hodnota = načtiDalší(parametry, ++index);
   111 				k.setRežimZamykání(RežimZamykání.najdiRežim(hodnota));
   112 				if (k.getRežimZamykání() == null)
   113 					throw new CLIParserException(
   114 						// TODO: překlad:
   115 						"Neplatný režim zamykání: " + hodnota);
   116 				return index - originalIndex;
   117 			}
   118 		},
   119 		DEFINICE_ATRIBUTU("--definice-atributu", "--attribute-definition") {
   120 			@Override
   121 			public int parsuj(String[] parametry, int index, Konfigurace k)
   122 				throws CLIParserException {
   123 				int originalIndex = index;
   124 				String název = načtiDalší(parametry, ++index);
   125 				String popis = načtiDalší(parametry, ++index);
   126 				k.addAtribut(new DefiniceAtributu(název, popis));
   127 				return index - originalIndex;
   128 			}
   129 		},
   130 		HODNOTA_ATRIBUTU("--hodnota", "--value") {
   131 			@Override
   132 			public int parsuj(String[] parametry, int index, Konfigurace k)
   133 				throws CLIParserException {
   134 				int originalIndex = index;
   135 				String hodnota = načtiDalší(parametry, ++index);
   136 				String popis = načtiDalší(parametry, ++index);
   137 
   138 				if (k.getAtributy().isEmpty())
   139 					throw new CLIParserException(
   140 						překlady.getString("chyba.cli.chybíDefiniceAtributu"));
   141 
   142 				k.getAtributy()
   143 					.get(k.getAtributy().size() - 1)
   144 					.addHodnota(new DefiniceHodnoty(hodnota, popis));
   145 
   146 				return index - originalIndex;
   147 			}
   148 		};
   149 
   150 		private final Collection<String> parametry;
   151 
   152 		private Token(String... parametry) {
   153 			this.parametry = Arrays.asList(parametry);
   154 		}
   155 
   156 		/**
   157 		 * @param parametr e.g. „--input-file“
   158 		 * @return whether option is this token
   159 		 */
   160 		public boolean odpovídá(String parametr) {
   161 			return parametry.contains(parametr);
   162 		}
   163 
   164 		/**
   165 		 * Parse String arguments and fill values into the options object.
   166 		 *
   167 		 * @param parametry CLI arguments
   168 		 * @param index index of the option matched by this token, like
   169 		 * „--input-file“
   170 		 * @param k object to be filled
   171 		 * @return number of parsed arguments – if option has no arguments (just
   172 		 * boolean flag), return 0, otherwise return positive integer: number of
   173 		 * eaten arguments.
   174 		 * @throws CLIParserException
   175 		 */
   176 		public abstract int parsuj(String[] parametry, int index, Konfigurace k)
   177 			throws CLIParserException;
   178 	}
   179 }