diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 43317cbbb..616d1c19d 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,1085 +5,35 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1125,22 +75,23 @@
- {
- "keyToString": {
- "DefaultGoTemplateProperty": "Go File",
- "RunOnceActivity.go.format.on.save.advertiser.fired": "true",
- "RunOnceActivity.go.formatter.settings.were.checked": "true",
- "RunOnceActivity.go.migrated.go.modules.settings": "true",
- "RunOnceActivity.go.modules.go.list.on.any.changes.was.set": "true",
- "RunOnceActivity.go.watchers.conflict.with.on.save.actions.check.performed": "true",
- "WebServerToolWindowFactoryState": "false",
- "go.import.settings.migrated": "true",
- "last_opened_file_path": "/Users/mick",
- "node.js.detected.package.eslint": "true",
- "node.js.selected.package.eslint": "(autodetect)",
- "settings.editor.selected.configurable": "actions.on.save"
+
+}]]>
diff --git a/EXAMPLES.md b/EXAMPLES.md
index e69de29bb..61e86ec41 100644
--- a/EXAMPLES.md
+++ b/EXAMPLES.md
@@ -0,0 +1,341 @@
+# Examples of all known working commands
+
+## Authentication
+
+ GoSungrow api login
+
+
+## High-level info commands
+
+```
+Usage:
+ GoSungrow info [command]
+
+Available Commands:
+ get Info - Get info from iSolarCloud (table)
+ raw Info - Get info from iSolarCloud (raw)
+ json Info - Get info from iSolarCloud (json)
+ csv Info - Get info from iSolarCloud (json)
+ put Info - Set info on iSolarCloud
+```
+
+```
+Usage:
+ GoSungrow info get [command]
+
+Available Commands:
+ point-names Info - Get iSolarCloud point names.
+ mqtt Info - Get iSolarCloud MQTT service login details.
+ search-point-names Info - Get iSolarCloud search point names.
+ devices Info - Get iSolarCloud devices.
+ models Info - Get ALL iSolarCloud models.
+ templates Info - Get all defined templates.
+ template-points Info - List data points used in report template.
+ device-points Info - List all available device data points.
+```
+
+
+## Get device details
+
+ GoSungrow info get device
+ GoSungrow info get search-point-names
+ GoSungrow info get models
+
+
+## Templates
+
+```
+GoSungrow info get templates
+┏━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┓
+┃ Template Id ┃ Template Name ┃ Update On ┃
+┣━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━┫
+┃ 8042 │ Critical │ 2022-02-15 13:00:28 ┃
+┃ 8041 │ extras │ 2022-02-15 09:40:04 ┃
+┃ 8036 │ C │ 2022-02-15 09:31:35 ┃
+┃ 8039 │ v │ 2022-02-15 09:31:10 ┃
+┃ 8040 │ A │ 2022-02-15 09:30:56 ┃
+┃ 8034 │ Percent │ 2022-02-15 09:30:41 ┃
+┃ 8038 │ MWh │ 2022-02-15 09:09:22 ┃
+┃ 8037 │ MW │ 2022-02-15 09:03:22 ┃
+┃ 8033 │ kW │ 2022-02-15 09:01:19 ┃
+┃ 8035 │ Hours │ 2022-02-15 08:55:56 ┃
+┃ 8031 │ kWh │ 2022-02-15 07:57:36 ┃
+┃ 7981 │ Power │ 2022-02-09 10:03:40 ┃
+┗━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━┛
+```
+
+
+## High-level data commands
+
+```
+Usage:
+ GoSungrow data [command]
+
+Available Commands:
+ get Data - Get high-level data from iSolarCloud (table)
+ raw Data - Get high-level data from iSolarCloud (raw)
+ json Data - Get high-level data from iSolarCloud (json)
+ csv Data - Get high-level data from iSolarCloud (json)
+ graph Data - Get high-level data from iSolarCloud (graph)
+```
+
+```
+Usage:
+ GoSungrow data get [command]
+
+Available Commands:
+ stats Data - Get current inverter stats, (last 5 minutes).
+ template Data - Get data from report template.
+ points Data - Get points data for a specific date.
+ real-time Data - Get iSolarCloud real-time data.
+ psdetails Data - Get iSolarCloud ps details.
+```
+
+
+## General
+
+```
+GoSungrow data get stats
+┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━┓
+┃ Date ┃ Point Id ┃ Point Name ┃ Value ┃ Unit ┃
+┣━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━┫
+┃ 2022-10-08 09:55:00 │ 1129147.0 │ Co2 Reduce │ 0 │ kg ┃
+┃ 2022-10-08 09:55:00 │ 1129147.0 │ Co2 Reduce Total │ 5819 │ kg ┃
+┃ 2022-10-08 09:55:00 │ 1129147.0 │ Curr Power │ 788 │ W ┃
+┃ 2022-10-08 09:55:00 │ 1129147.0 │ Daily Irradiation │ -- │ ┃
+┃ 2022-10-08 09:55:00 │ 1129147.0 │ Equivalent Hour │ 0.27 │ Hour ┃
+
+...
+
+┃ 2022-10-08 09:55:00 │ 1171348.0 │ Today Income │ 0.397 │ AUD ┃
+┃ 2022-10-08 09:55:00 │ 1171348.0 │ Total Capacity │ │ ┃
+┃ 2022-10-08 09:55:00 │ 1171348.0 │ Total Energy │ 176.5 │ kWh ┃
+┃ 2022-10-08 09:55:00 │ 1171348.0 │ Total Income │ 35.806 │ AUD ┃
+┃ 2022-10-08 09:55:00 │ 1171348.0 │ Use Energy │ 6.7 │ kWh ┃
+┗━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━┷━━━━━━┛
+```
+
+
+
+## Templates
+
+```
+GoSungrow info get template-points 7981
+┏━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━┓
+┃ PointStruct Id ┃ Description ┃ Unit ┃
+┣━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━┫
+┃ 1129147_11_0_0.p83032 │ Meter AC Power │ kW ┃
+┃ 1129147_11_0_0.p83119 │ Daily Feed-in Energy (PV) │ kWh ┃
+┃ 1129147_11_0_0.p83549 │ Grid active power │ kW ┃
+┃ 1129147_11_0_0.p83002 │ Inverter AC Power │ kW ┃
+┃ 1129147_11_0_0.p83011 │ Meter E-daily Consumption │ kWh ┃
+┃ 1129147_11_0_0.p83022 │ Daily Yield of Plant │ kWh ┃
+┃ 1129147_11_0_0.p83006 │ Meter Daily Yield │ kWh ┃
+┃ 1129147_11_0_0.p83033 │ Plant Power │ kW ┃
+┃ 1129147_11_0_0.p83072 │ Daily Feed-in Energy │ kWh ┃
+┃ 1129147_11_0_0.p83097 │ Daily Load Energy Consumption from PV │ kWh ┃
+┃ 1129147_11_0_0.p83102 │ Daily Purchased Energy │ kWh ┃
+┃ 1129147_14_1_1.p13028 │ Daily Battery Charging Energy │ kWh ┃
+┃ 1129147_14_1_1.p13112 │ Daily PV Yield │ kWh ┃
+┃ 1129147_14_1_1.p13147 │ Daily Purchased Energy │ kWh ┃
+┃ 1129147_14_1_1.p13173 │ Daily Feed-in Energy (PV) │ kWh ┃
+┃ 1129147_14_1_1.p13174 │ Daily Battery Charging Energy from PV │ kWh ┃
+┃ 1129147_14_1_1.p13199 │ Daily Load Energy Consumption │ kWh ┃
+┃ 1129147_14_1_1.p13116 │ Daily Load Energy Consumption from PV │ kWh ┃
+┃ 1129147_14_1_1.p13122 │ Daily Feed-in Energy │ kWh ┃
+┗━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━┛
+```
+
+```
+GoSungrow data get template 8042 20220212
+┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━┓
+┃ Date/Time ┃ Point Id ┃ Point Name ┃ Value ┃ Units ┃
+┣━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━┫
+┃ 2022-02-12 00:00:00 │ 1129147_11_0_0.p83106 │ Load Power │ 396 │ kW ┃
+┃ 2022-02-12 00:05:00 │ 1129147_11_0_0.p83106 │ Load Power │ 480 │ kW ┃
+┃ 2022-02-12 00:10:00 │ 1129147_11_0_0.p83106 │ Load Power │ 487 │ kW ┃
+┃ 2022-02-12 00:15:00 │ 1129147_11_0_0.p83106 │ Load Power │ 497 │ kW ┃
+┃ 2022-02-12 00:20:00 │ 1129147_11_0_0.p83106 │ Load Power │ 524 │ kW ┃
+┃ 2022-02-12 00:25:00 │ 1129147_11_0_0.p83106 │ Load Power │ 541 │ kW ┃
+┃ 2022-02-12 00:30:00 │ 1129147_11_0_0.p83106 │ Load Power │ 554 │ kW ┃
+
+...
+
+┃ 2022-02-12 23:55:00 │ 1129147_14_1_1.p13019 │ Internal Air Temperature │ 19.4 │ ℃ ┃
+┃ 2022-02-13 00:00:00 │ 1129147_14_1_1.p13019 │ Internal Air Temperature │ 22.3 │ ℃ ┃
+┗━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━┷━━━━━━━┛
+```
+
+ GoSungrow data graph template 8042 20220212 '{"search_string":"p13019","min_left_axis":-6000,"max_left_axis":12000}'
+ GoSungrow data graph template 8042 20220212 '{"search_string":"p13019"}'
+ GoSungrow data graph template 8042 20220212 '{"search_string":"p83106","min_left_axis":-6000,"max_left_axis":12000}'
+ GoSungrow data graph template 8042 20220212 '{"search_string":"p83106"}'
+ GoSungrow data graph template 8042 20220212 '{"title":"Testing 1. 2. 3.","time_column":"1","value_column":"4","search_column":"3","search_string":"p83106","file_name":"foo.png"}'
+ GoSungrow data graph template 8042 20220212 '{"title":"Testing 1. 2. 3.","time_column":1,"value_column":4,"search_column":2,"search_string":"p13019","min_left_axis":0,"max_left_axis":0}'
+ GoSungrow data graph template 8042 20220212 '{"title":"Testing 1. 2. 3.","time_column":1,"value_column":4,"search_column":2,"search_string":"p13149","min_left_axis":0,"max_left_axis":0}'
+ GoSungrow data graph template 8042 20220212 '{"title":"Testing 1. 2. 3.","time_column":1,"value_column":4,"search_column":2,"search_string":"p83106","file_name":"foo.png"}'
+ GoSungrow data graph template 8042 20220212 '{"title":"Testing 1. 2. 3.","time_column":1,"value_column":4,"search_column":2,"search_string":"p83106","min_left_axis":-6000,"max_left_axis":1000}'
+ GoSungrow data graph template 8042 20220212 '{"title":"Testing 1. 2. 3.","time_column":1,"value_column":4,"search_column":2,"search_string":"p83106","min_left_axis":-6000,"max_left_axis":12000}'
+ GoSungrow data graph template 8042 20220212 '{"title":"Testing 1. 2. 3.","time_column":1,"value_column":4,"search_column":2,"search_string":"p83106","min_left_axis":-6000,"max_left_axis":42000}'
+ GoSungrow data graph template 8042 20220212 '{"title":"Testing 1. 2. 3.","time_column":1,"value_column":4,"search_column":2,"search_string":"p83106","min_left_axis":0,"max_left_axis":0}'
+ GoSungrow data graph template 8042 20220212 '{"title":"Testing 1. 2. 3.","time_column":1,"value_column":4,"search_column":3,"search_string":"p83106","file_name":"foo.png"}'
+ GoSungrow data raw template '' 20220201
+ GoSungrow data save template '' 20220201
+ GoSungrow data save template 8042 20220212
+
+
+## Hacking
+
+
+## Base API commands
+
+```
+Usage:
+GoSungrow api [command]
+
+Examples:
+GoSungrow api login
+GoSungrow api get
+GoSungrow api raw
+GoSungrow api save
+GoSungrow api put
+
+Available Commands:
+ls List iSolarCloud api endpoints/areas
+login Login to iSolarCloud
+get Get details from iSolarCloud
+raw Raw details from iSolarCloud
+save Save details from iSolarCloud as JSON
+put Put details onto iSolarCloud
+```
+
+## Get device details
+
+ GoSungrow api get getPsList
+ GoSungrow api get getPsListByName
+ GoSungrow api get getPsDataSupplementTaskList
+ GoSungrow api get getPsUser
+ GoSungrow api get queryPsIdList
+ GoSungrow api get getInstallInfoList
+ GoSungrow api get getPsListStaticData
+ GoSungrow api get queryAllPsIdAndName
+ GoSungrow api get getPsDetail '{"ps_id":"1171348"}'
+ GoSungrow api get getPsDetailWithPsType '{"ps_id":"1171348"}'
+ GoSungrow api get getPsHealthState '{"ps_id":"1171348"}'
+ GoSungrow api get getPsWeatherList '{"ps_id":"1171348"}'
+ GoSungrow api get queryDeviceList '{"ps_id":"1171348"}'
+ GoSungrow api get queryDeviceListByUserId '{"ps_id":"1171348"}'
+ GoSungrow api get queryDeviceListForApp '{"ps_id":"1171348"}'
+ GoSungrow api get findPsType '{"ps_id":"1171348"}'
+ GoSungrow api get getDeviceList '{"ps_id":"1171348"}'
+ GoSungrow api get getIncomeSettingInfos '{"ps_id":"1171348"}'
+ GoSungrow api get getPowerChargeSettingInfo '{"ps_id":"1171348"}'
+ GoSungrow api get getPowerStationInfo '{"ps_id":"1171348"}'
+ GoSungrow api get WebAppService.getDeviceUuid '{"ps_key":"1171348"}'
+ GoSungrow api get getPowerStationForHousehold '{"ps_id":"1171348"}'
+
+
+## Get device data
+
+ GoSungrow api get energyTrend
+ GoSungrow api get getKpiInfo
+ GoSungrow api get queryPsProfit '{"date_id":"20221001","date_type":"1","ps_id":"1171348"}'
+ GoSungrow api get getPowerStationData '{"date_id":"20221001","date_type":"1","ps_id":"1171348"}'
+ GoSungrow api get getHouseholdStoragePsReport '{"date_id":"20221001","date_type":"1","ps_id":"1171348"}'
+ GoSungrow api get queryPsProfit '{"date_id":"202210","date_type":"2","ps_id":"1171348"}'
+ GoSungrow api get getPowerStationData '{"date_id":"202210","date_type":"2","ps_id":"1171348"}'
+ GoSungrow api get getHouseholdStoragePsReport '{"date_id":"202210","date_type":"2","ps_id":"1171348"}'
+ GoSungrow api get queryPsProfit '{"date_id":"2022","date_type":"3","ps_id":"1171348"}'
+ GoSungrow api get getPowerStationData '{"date_id":"2022","date_type":"3","ps_id":"1171348"}'
+ GoSungrow api get getHouseholdStoragePsReport '{"date_id":"2022","date_type":"3","ps_id":"1171348"}'
+ GoSungrow api get getPowerTrendDayData '{"BeginTime":"20221004"}'
+ GoSungrow api get getPowerStatistics '{"ps_id":"1171348"}'
+ GoSungrow api get WebAppService.showPSView '{"ps_id":"1171348"}'
+
+
+## Reports
+
+ GoSungrow api get getPsReport '{"report_type":"1","date_id":"20220201","date_type":"1","ps_id":"1171348"}'
+ GoSungrow api get getPsReport '{"report_type":"1","date_id":"20220201","date_type":"2","ps_id":"1171348"}'
+ GoSungrow api get getPsReport '{"report_type":"1","date_id":"20220201","date_type":"3","ps_id":"1171348"}'
+ GoSungrow api get reportList '{"ps_id":"1171348","report_type":"1"}'
+ GoSungrow api get reportList '{"ps_id":"1171348","report_type":"2"}'
+ GoSungrow api get reportList '{"ps_id":"1171348","report_type":"3"}'
+ GoSungrow api get reportList '{"ps_id":"1171348","report_type":"4"}'
+
+
+## Templates
+
+ GoSungrow api get template 20220202
+ GoSungrow api get template 8042 20220212
+ GoSungrow api get getTemplateList
+ GoSungrow api get WebAppService.queryUserCurveTemplateData '{"template_id":"8042","date_type":"1","start_time":"20220223000000","end_time":"20220223235900"}'
+
+
+## User/installer/support info
+
+ GoSungrow api get getUserList
+ GoSungrow api get getUserPsOrderList
+ GoSungrow api get getPhotoInfo
+ GoSungrow api get getOrgListByName
+ GoSungrow api get getOrgListByUserId
+ GoSungrow api get getOrgListForUser
+ GoSungrow api get queryUserList
+ GoSungrow api get getInstallerInfoByDealerOrgCodeOrId '{"dealer_org_code":"AUSCEKK7"}'
+ GoSungrow api get getInstallerInfoByDealerOrgCodeOrId '{"org_id":"362245"}'
+ GoSungrow api get getInstallerInfoByDealerOrgCodeOrId '{"org_id":"80384"}'
+ GoSungrow api get getInstallerInfoByDealerOrgCodeOrId '{"org_id":"80393"}'
+ GoSungrow api get getInstallerInfoByDealerOrgCodeOrId '{"org_id":"300977"}'
+
+
+## Meta-data
+
+ GoSungrow api get getDeviceTypeInfoList
+ GoSungrow api get getDeviceTypeList
+ GoSungrow api get getInvertDataList
+ GoSungrow api get getModuleLogTaskList
+ GoSungrow api get powerDevicePointList
+ GoSungrow api get getPowerDevicePointNames '{"device_type":"1"}'
+ GoSungrow api get getPowerDevicePointNames '{"device_type":"2"}'
+ GoSungrow api get getPowerDevicePointNames '{"device_type":"7"}'
+ GoSungrow api get getDeviceModelInfoList
+ GoSungrow api get queryUnitList
+ GoSungrow api get getPowerSettingCharges
+ GoSungrow api get getPowerDevicePointNames '{"device_type":"1"}'
+ GoSungrow api get getPowerDeviceModelTechList '{"device_type":"1"}'
+ GoSungrow api get getPowerDevicePointInfo '{"id":"1"}'
+
+
+## Task commands
+
+ GoSungrow api get queryBatchCreatePsTaskList
+ GoSungrow api get getPowerDeviceSetTaskDetailList '{"query_type":"2","task_id":"1","uuid":"844763"}'
+ GoSungrow api get getPowerDeviceSetTaskDetailList '{"query_type":"7","task_id":"1","uuid":"844763"}'
+ GoSungrow api get getPowerDeviceSetTaskDetailList '{"size":0,"curPage":0}'
+ GoSungrow api get getPowerDeviceSetTaskList '{"size":0,"curPage":0}'
+ GoSungrow api get getPowerDeviceSetTaskList '{"size":0,"curPage":1}'
+ GoSungrow api get getRemoteUpgradeSubTasksList '{"query_type":"1","task_id":"1577700"}'
+ GoSungrow api get getRemoteUpgradeTaskList '{"ps_id_list":"1171348"}'
+
+
+## Misc commands
+
+ GoSungrow api get getDevicePoints '{"point_id":"13003"}'
+ GoSungrow api get getPowerPictureList
+
+
+## Hacking
+
+ GoSungrow api get checkUnitStatus
+ GoSungrow api get getAllPowerDeviceSetName
+ GoSungrow api get getAreaList
+ GoSungrow api get getCloudList
+ GoSungrow api get getConfigList
+ GoSungrow api get getDeviceInfo
+ GoSungrow api get getOSSConfig
+ GoSungrow api get getOssObjectStream
+ GoSungrow api get getEncryptPublicKey
+ GoSungrow api get getFaultCount
+ GoSungrow api get getFaultDetail '{"fault_code":"34"}'
+ GoSungrow api get getFaultMsgByFaultCode '{"fault_code":"703"}'
+ GoSungrow api get getFaultMsgListWithYYYYMM
diff --git a/config.json b/config.json
index 8cf2f654f..a7ea9f522 100644
--- a/config.json
+++ b/config.json
@@ -1,6 +1,6 @@
{
"appkey": "93D72E60331ABDCDC7B39ADC2D1F32B3",
- "config": "/Users/mick/.GoSungrow/config.json",
+ "config": "",
"debug": false,
"host": "https://augateway.isolarcloud.com",
"password": "",
@@ -8,4 +8,4 @@
"timeout": "30s",
"token-expiry": "",
"user": ""
-}
\ No newline at end of file
+}
diff --git a/defaults/EXAMPLES.md b/defaults/EXAMPLES.md
index e69de29bb..61e86ec41 100644
--- a/defaults/EXAMPLES.md
+++ b/defaults/EXAMPLES.md
@@ -0,0 +1,341 @@
+# Examples of all known working commands
+
+## Authentication
+
+ GoSungrow api login
+
+
+## High-level info commands
+
+```
+Usage:
+ GoSungrow info [command]
+
+Available Commands:
+ get Info - Get info from iSolarCloud (table)
+ raw Info - Get info from iSolarCloud (raw)
+ json Info - Get info from iSolarCloud (json)
+ csv Info - Get info from iSolarCloud (json)
+ put Info - Set info on iSolarCloud
+```
+
+```
+Usage:
+ GoSungrow info get [command]
+
+Available Commands:
+ point-names Info - Get iSolarCloud point names.
+ mqtt Info - Get iSolarCloud MQTT service login details.
+ search-point-names Info - Get iSolarCloud search point names.
+ devices Info - Get iSolarCloud devices.
+ models Info - Get ALL iSolarCloud models.
+ templates Info - Get all defined templates.
+ template-points Info - List data points used in report template.
+ device-points Info - List all available device data points.
+```
+
+
+## Get device details
+
+ GoSungrow info get device
+ GoSungrow info get search-point-names
+ GoSungrow info get models
+
+
+## Templates
+
+```
+GoSungrow info get templates
+┏━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┓
+┃ Template Id ┃ Template Name ┃ Update On ┃
+┣━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━┫
+┃ 8042 │ Critical │ 2022-02-15 13:00:28 ┃
+┃ 8041 │ extras │ 2022-02-15 09:40:04 ┃
+┃ 8036 │ C │ 2022-02-15 09:31:35 ┃
+┃ 8039 │ v │ 2022-02-15 09:31:10 ┃
+┃ 8040 │ A │ 2022-02-15 09:30:56 ┃
+┃ 8034 │ Percent │ 2022-02-15 09:30:41 ┃
+┃ 8038 │ MWh │ 2022-02-15 09:09:22 ┃
+┃ 8037 │ MW │ 2022-02-15 09:03:22 ┃
+┃ 8033 │ kW │ 2022-02-15 09:01:19 ┃
+┃ 8035 │ Hours │ 2022-02-15 08:55:56 ┃
+┃ 8031 │ kWh │ 2022-02-15 07:57:36 ┃
+┃ 7981 │ Power │ 2022-02-09 10:03:40 ┃
+┗━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━┛
+```
+
+
+## High-level data commands
+
+```
+Usage:
+ GoSungrow data [command]
+
+Available Commands:
+ get Data - Get high-level data from iSolarCloud (table)
+ raw Data - Get high-level data from iSolarCloud (raw)
+ json Data - Get high-level data from iSolarCloud (json)
+ csv Data - Get high-level data from iSolarCloud (json)
+ graph Data - Get high-level data from iSolarCloud (graph)
+```
+
+```
+Usage:
+ GoSungrow data get [command]
+
+Available Commands:
+ stats Data - Get current inverter stats, (last 5 minutes).
+ template Data - Get data from report template.
+ points Data - Get points data for a specific date.
+ real-time Data - Get iSolarCloud real-time data.
+ psdetails Data - Get iSolarCloud ps details.
+```
+
+
+## General
+
+```
+GoSungrow data get stats
+┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━┓
+┃ Date ┃ Point Id ┃ Point Name ┃ Value ┃ Unit ┃
+┣━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━┫
+┃ 2022-10-08 09:55:00 │ 1129147.0 │ Co2 Reduce │ 0 │ kg ┃
+┃ 2022-10-08 09:55:00 │ 1129147.0 │ Co2 Reduce Total │ 5819 │ kg ┃
+┃ 2022-10-08 09:55:00 │ 1129147.0 │ Curr Power │ 788 │ W ┃
+┃ 2022-10-08 09:55:00 │ 1129147.0 │ Daily Irradiation │ -- │ ┃
+┃ 2022-10-08 09:55:00 │ 1129147.0 │ Equivalent Hour │ 0.27 │ Hour ┃
+
+...
+
+┃ 2022-10-08 09:55:00 │ 1171348.0 │ Today Income │ 0.397 │ AUD ┃
+┃ 2022-10-08 09:55:00 │ 1171348.0 │ Total Capacity │ │ ┃
+┃ 2022-10-08 09:55:00 │ 1171348.0 │ Total Energy │ 176.5 │ kWh ┃
+┃ 2022-10-08 09:55:00 │ 1171348.0 │ Total Income │ 35.806 │ AUD ┃
+┃ 2022-10-08 09:55:00 │ 1171348.0 │ Use Energy │ 6.7 │ kWh ┃
+┗━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━┷━━━━━━┛
+```
+
+
+
+## Templates
+
+```
+GoSungrow info get template-points 7981
+┏━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━┓
+┃ PointStruct Id ┃ Description ┃ Unit ┃
+┣━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━┫
+┃ 1129147_11_0_0.p83032 │ Meter AC Power │ kW ┃
+┃ 1129147_11_0_0.p83119 │ Daily Feed-in Energy (PV) │ kWh ┃
+┃ 1129147_11_0_0.p83549 │ Grid active power │ kW ┃
+┃ 1129147_11_0_0.p83002 │ Inverter AC Power │ kW ┃
+┃ 1129147_11_0_0.p83011 │ Meter E-daily Consumption │ kWh ┃
+┃ 1129147_11_0_0.p83022 │ Daily Yield of Plant │ kWh ┃
+┃ 1129147_11_0_0.p83006 │ Meter Daily Yield │ kWh ┃
+┃ 1129147_11_0_0.p83033 │ Plant Power │ kW ┃
+┃ 1129147_11_0_0.p83072 │ Daily Feed-in Energy │ kWh ┃
+┃ 1129147_11_0_0.p83097 │ Daily Load Energy Consumption from PV │ kWh ┃
+┃ 1129147_11_0_0.p83102 │ Daily Purchased Energy │ kWh ┃
+┃ 1129147_14_1_1.p13028 │ Daily Battery Charging Energy │ kWh ┃
+┃ 1129147_14_1_1.p13112 │ Daily PV Yield │ kWh ┃
+┃ 1129147_14_1_1.p13147 │ Daily Purchased Energy │ kWh ┃
+┃ 1129147_14_1_1.p13173 │ Daily Feed-in Energy (PV) │ kWh ┃
+┃ 1129147_14_1_1.p13174 │ Daily Battery Charging Energy from PV │ kWh ┃
+┃ 1129147_14_1_1.p13199 │ Daily Load Energy Consumption │ kWh ┃
+┃ 1129147_14_1_1.p13116 │ Daily Load Energy Consumption from PV │ kWh ┃
+┃ 1129147_14_1_1.p13122 │ Daily Feed-in Energy │ kWh ┃
+┗━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━┛
+```
+
+```
+GoSungrow data get template 8042 20220212
+┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━┓
+┃ Date/Time ┃ Point Id ┃ Point Name ┃ Value ┃ Units ┃
+┣━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━┫
+┃ 2022-02-12 00:00:00 │ 1129147_11_0_0.p83106 │ Load Power │ 396 │ kW ┃
+┃ 2022-02-12 00:05:00 │ 1129147_11_0_0.p83106 │ Load Power │ 480 │ kW ┃
+┃ 2022-02-12 00:10:00 │ 1129147_11_0_0.p83106 │ Load Power │ 487 │ kW ┃
+┃ 2022-02-12 00:15:00 │ 1129147_11_0_0.p83106 │ Load Power │ 497 │ kW ┃
+┃ 2022-02-12 00:20:00 │ 1129147_11_0_0.p83106 │ Load Power │ 524 │ kW ┃
+┃ 2022-02-12 00:25:00 │ 1129147_11_0_0.p83106 │ Load Power │ 541 │ kW ┃
+┃ 2022-02-12 00:30:00 │ 1129147_11_0_0.p83106 │ Load Power │ 554 │ kW ┃
+
+...
+
+┃ 2022-02-12 23:55:00 │ 1129147_14_1_1.p13019 │ Internal Air Temperature │ 19.4 │ ℃ ┃
+┃ 2022-02-13 00:00:00 │ 1129147_14_1_1.p13019 │ Internal Air Temperature │ 22.3 │ ℃ ┃
+┗━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━┷━━━━━━━┛
+```
+
+ GoSungrow data graph template 8042 20220212 '{"search_string":"p13019","min_left_axis":-6000,"max_left_axis":12000}'
+ GoSungrow data graph template 8042 20220212 '{"search_string":"p13019"}'
+ GoSungrow data graph template 8042 20220212 '{"search_string":"p83106","min_left_axis":-6000,"max_left_axis":12000}'
+ GoSungrow data graph template 8042 20220212 '{"search_string":"p83106"}'
+ GoSungrow data graph template 8042 20220212 '{"title":"Testing 1. 2. 3.","time_column":"1","value_column":"4","search_column":"3","search_string":"p83106","file_name":"foo.png"}'
+ GoSungrow data graph template 8042 20220212 '{"title":"Testing 1. 2. 3.","time_column":1,"value_column":4,"search_column":2,"search_string":"p13019","min_left_axis":0,"max_left_axis":0}'
+ GoSungrow data graph template 8042 20220212 '{"title":"Testing 1. 2. 3.","time_column":1,"value_column":4,"search_column":2,"search_string":"p13149","min_left_axis":0,"max_left_axis":0}'
+ GoSungrow data graph template 8042 20220212 '{"title":"Testing 1. 2. 3.","time_column":1,"value_column":4,"search_column":2,"search_string":"p83106","file_name":"foo.png"}'
+ GoSungrow data graph template 8042 20220212 '{"title":"Testing 1. 2. 3.","time_column":1,"value_column":4,"search_column":2,"search_string":"p83106","min_left_axis":-6000,"max_left_axis":1000}'
+ GoSungrow data graph template 8042 20220212 '{"title":"Testing 1. 2. 3.","time_column":1,"value_column":4,"search_column":2,"search_string":"p83106","min_left_axis":-6000,"max_left_axis":12000}'
+ GoSungrow data graph template 8042 20220212 '{"title":"Testing 1. 2. 3.","time_column":1,"value_column":4,"search_column":2,"search_string":"p83106","min_left_axis":-6000,"max_left_axis":42000}'
+ GoSungrow data graph template 8042 20220212 '{"title":"Testing 1. 2. 3.","time_column":1,"value_column":4,"search_column":2,"search_string":"p83106","min_left_axis":0,"max_left_axis":0}'
+ GoSungrow data graph template 8042 20220212 '{"title":"Testing 1. 2. 3.","time_column":1,"value_column":4,"search_column":3,"search_string":"p83106","file_name":"foo.png"}'
+ GoSungrow data raw template '' 20220201
+ GoSungrow data save template '' 20220201
+ GoSungrow data save template 8042 20220212
+
+
+## Hacking
+
+
+## Base API commands
+
+```
+Usage:
+GoSungrow api [command]
+
+Examples:
+GoSungrow api login
+GoSungrow api get
+GoSungrow api raw
+GoSungrow api save
+GoSungrow api put
+
+Available Commands:
+ls List iSolarCloud api endpoints/areas
+login Login to iSolarCloud
+get Get details from iSolarCloud
+raw Raw details from iSolarCloud
+save Save details from iSolarCloud as JSON
+put Put details onto iSolarCloud
+```
+
+## Get device details
+
+ GoSungrow api get getPsList
+ GoSungrow api get getPsListByName
+ GoSungrow api get getPsDataSupplementTaskList
+ GoSungrow api get getPsUser
+ GoSungrow api get queryPsIdList
+ GoSungrow api get getInstallInfoList
+ GoSungrow api get getPsListStaticData
+ GoSungrow api get queryAllPsIdAndName
+ GoSungrow api get getPsDetail '{"ps_id":"1171348"}'
+ GoSungrow api get getPsDetailWithPsType '{"ps_id":"1171348"}'
+ GoSungrow api get getPsHealthState '{"ps_id":"1171348"}'
+ GoSungrow api get getPsWeatherList '{"ps_id":"1171348"}'
+ GoSungrow api get queryDeviceList '{"ps_id":"1171348"}'
+ GoSungrow api get queryDeviceListByUserId '{"ps_id":"1171348"}'
+ GoSungrow api get queryDeviceListForApp '{"ps_id":"1171348"}'
+ GoSungrow api get findPsType '{"ps_id":"1171348"}'
+ GoSungrow api get getDeviceList '{"ps_id":"1171348"}'
+ GoSungrow api get getIncomeSettingInfos '{"ps_id":"1171348"}'
+ GoSungrow api get getPowerChargeSettingInfo '{"ps_id":"1171348"}'
+ GoSungrow api get getPowerStationInfo '{"ps_id":"1171348"}'
+ GoSungrow api get WebAppService.getDeviceUuid '{"ps_key":"1171348"}'
+ GoSungrow api get getPowerStationForHousehold '{"ps_id":"1171348"}'
+
+
+## Get device data
+
+ GoSungrow api get energyTrend
+ GoSungrow api get getKpiInfo
+ GoSungrow api get queryPsProfit '{"date_id":"20221001","date_type":"1","ps_id":"1171348"}'
+ GoSungrow api get getPowerStationData '{"date_id":"20221001","date_type":"1","ps_id":"1171348"}'
+ GoSungrow api get getHouseholdStoragePsReport '{"date_id":"20221001","date_type":"1","ps_id":"1171348"}'
+ GoSungrow api get queryPsProfit '{"date_id":"202210","date_type":"2","ps_id":"1171348"}'
+ GoSungrow api get getPowerStationData '{"date_id":"202210","date_type":"2","ps_id":"1171348"}'
+ GoSungrow api get getHouseholdStoragePsReport '{"date_id":"202210","date_type":"2","ps_id":"1171348"}'
+ GoSungrow api get queryPsProfit '{"date_id":"2022","date_type":"3","ps_id":"1171348"}'
+ GoSungrow api get getPowerStationData '{"date_id":"2022","date_type":"3","ps_id":"1171348"}'
+ GoSungrow api get getHouseholdStoragePsReport '{"date_id":"2022","date_type":"3","ps_id":"1171348"}'
+ GoSungrow api get getPowerTrendDayData '{"BeginTime":"20221004"}'
+ GoSungrow api get getPowerStatistics '{"ps_id":"1171348"}'
+ GoSungrow api get WebAppService.showPSView '{"ps_id":"1171348"}'
+
+
+## Reports
+
+ GoSungrow api get getPsReport '{"report_type":"1","date_id":"20220201","date_type":"1","ps_id":"1171348"}'
+ GoSungrow api get getPsReport '{"report_type":"1","date_id":"20220201","date_type":"2","ps_id":"1171348"}'
+ GoSungrow api get getPsReport '{"report_type":"1","date_id":"20220201","date_type":"3","ps_id":"1171348"}'
+ GoSungrow api get reportList '{"ps_id":"1171348","report_type":"1"}'
+ GoSungrow api get reportList '{"ps_id":"1171348","report_type":"2"}'
+ GoSungrow api get reportList '{"ps_id":"1171348","report_type":"3"}'
+ GoSungrow api get reportList '{"ps_id":"1171348","report_type":"4"}'
+
+
+## Templates
+
+ GoSungrow api get template 20220202
+ GoSungrow api get template 8042 20220212
+ GoSungrow api get getTemplateList
+ GoSungrow api get WebAppService.queryUserCurveTemplateData '{"template_id":"8042","date_type":"1","start_time":"20220223000000","end_time":"20220223235900"}'
+
+
+## User/installer/support info
+
+ GoSungrow api get getUserList
+ GoSungrow api get getUserPsOrderList
+ GoSungrow api get getPhotoInfo
+ GoSungrow api get getOrgListByName
+ GoSungrow api get getOrgListByUserId
+ GoSungrow api get getOrgListForUser
+ GoSungrow api get queryUserList
+ GoSungrow api get getInstallerInfoByDealerOrgCodeOrId '{"dealer_org_code":"AUSCEKK7"}'
+ GoSungrow api get getInstallerInfoByDealerOrgCodeOrId '{"org_id":"362245"}'
+ GoSungrow api get getInstallerInfoByDealerOrgCodeOrId '{"org_id":"80384"}'
+ GoSungrow api get getInstallerInfoByDealerOrgCodeOrId '{"org_id":"80393"}'
+ GoSungrow api get getInstallerInfoByDealerOrgCodeOrId '{"org_id":"300977"}'
+
+
+## Meta-data
+
+ GoSungrow api get getDeviceTypeInfoList
+ GoSungrow api get getDeviceTypeList
+ GoSungrow api get getInvertDataList
+ GoSungrow api get getModuleLogTaskList
+ GoSungrow api get powerDevicePointList
+ GoSungrow api get getPowerDevicePointNames '{"device_type":"1"}'
+ GoSungrow api get getPowerDevicePointNames '{"device_type":"2"}'
+ GoSungrow api get getPowerDevicePointNames '{"device_type":"7"}'
+ GoSungrow api get getDeviceModelInfoList
+ GoSungrow api get queryUnitList
+ GoSungrow api get getPowerSettingCharges
+ GoSungrow api get getPowerDevicePointNames '{"device_type":"1"}'
+ GoSungrow api get getPowerDeviceModelTechList '{"device_type":"1"}'
+ GoSungrow api get getPowerDevicePointInfo '{"id":"1"}'
+
+
+## Task commands
+
+ GoSungrow api get queryBatchCreatePsTaskList
+ GoSungrow api get getPowerDeviceSetTaskDetailList '{"query_type":"2","task_id":"1","uuid":"844763"}'
+ GoSungrow api get getPowerDeviceSetTaskDetailList '{"query_type":"7","task_id":"1","uuid":"844763"}'
+ GoSungrow api get getPowerDeviceSetTaskDetailList '{"size":0,"curPage":0}'
+ GoSungrow api get getPowerDeviceSetTaskList '{"size":0,"curPage":0}'
+ GoSungrow api get getPowerDeviceSetTaskList '{"size":0,"curPage":1}'
+ GoSungrow api get getRemoteUpgradeSubTasksList '{"query_type":"1","task_id":"1577700"}'
+ GoSungrow api get getRemoteUpgradeTaskList '{"ps_id_list":"1171348"}'
+
+
+## Misc commands
+
+ GoSungrow api get getDevicePoints '{"point_id":"13003"}'
+ GoSungrow api get getPowerPictureList
+
+
+## Hacking
+
+ GoSungrow api get checkUnitStatus
+ GoSungrow api get getAllPowerDeviceSetName
+ GoSungrow api get getAreaList
+ GoSungrow api get getCloudList
+ GoSungrow api get getConfigList
+ GoSungrow api get getDeviceInfo
+ GoSungrow api get getOSSConfig
+ GoSungrow api get getOssObjectStream
+ GoSungrow api get getEncryptPublicKey
+ GoSungrow api get getFaultCount
+ GoSungrow api get getFaultDetail '{"fault_code":"34"}'
+ GoSungrow api get getFaultMsgByFaultCode '{"fault_code":"703"}'
+ GoSungrow api get getFaultMsgListWithYYYYMM
diff --git a/defaults/const.go b/defaults/const.go
index 65065ca05..609d3c110 100644
--- a/defaults/const.go
+++ b/defaults/const.go
@@ -15,7 +15,7 @@ var Examples string
const (
Description = "GoSungrow - GoLang implementation to access the iSolarCloud API updated by SunGrow inverters"
BinaryName = "GoSungrow"
- BinaryVersion = "2.2.1"
+ BinaryVersion = "2.3.0"
SourceRepo = "github.com/MickMake/" + BinaryName
BinaryRepo = "github.com/MickMake/" + BinaryName
diff --git a/examples.txt b/examples.txt
index 1e4984a72..cd2a1278f 100644
--- a/examples.txt
+++ b/examples.txt
@@ -1,3 +1,6 @@
+GoSungrow api login
+GoSungrow api ls areas
+
GoSungrow api get WebAppService.getDeviceUuid '{"ps_key":"1171348"}'
GoSungrow api get WebAppService.showPSView '{"ps_id":"1171348"}'
GoSungrow api get checkUnitStatus
@@ -53,8 +56,6 @@ GoSungrow api get reportList '{"ps_id":"1171348","report_type":"1"}'
GoSungrow api get reportList '{"ps_id":"1171348","report_type":"2"}'
GoSungrow api get reportList '{"ps_id":"1171348","report_type":"3"}'
GoSungrow api get reportList '{"ps_id":"1171348","report_type":"4"}'
-GoSungrow api login
-GoSungrow api ls areas
GoSungrow api raw queryDeviceList '{"ps_id":"1171348"}'
GoSungrow api save WebAppService.queryUserCurveTemplateData '{"template_id":"8042","date_type":"1","start_time":"20220223000000","end_time":"20220223235900"}'
GoSungrow api save getPsDetail '{"ps_id":""}'
@@ -72,6 +73,7 @@ GoSungrow data get template 8042 20220227
GoSungrow data get template-points 8040
GoSungrow data get template-points 8041
GoSungrow data get template-points 8042
+
GoSungrow data graph template 8042 20220212 '{"search_string":"p13019","min_left_axis":-6000,"max_left_axis":12000}'
GoSungrow data graph template 8042 20220212 '{"search_string":"p13019"}'
GoSungrow data graph template 8042 20220212 '{"search_string":"p83106","min_left_axis":-6000,"max_left_axis":12000}'
@@ -90,21 +92,17 @@ GoSungrow data save template '' 20220201
GoSungrow data save template 8042 20220212
GoSungrow get raw template 20220202
GoSungrow get template 8042 20220212
-
GoSungrow data get stats
GoSungrow data get search-point-names
GoSungrow data get device
GoSungrow data get model
-
GoSungrow api raw getPowerStationForHousehold '{"ps_id":"1171348"}'
> "org_index_code":"|80384|80393|300977|",
-
GoSungrow api raw getInstallerInfoByDealerOrgCodeOrId '{"dealer_org_code":"AUSCEKK7"}'
GoSungrow api raw getInstallerInfoByDealerOrgCodeOrId '{"org_id":"362245"}'
GoSungrow api raw getInstallerInfoByDealerOrgCodeOrId '{"org_id":"80384"}'
GoSungrow api raw getInstallerInfoByDealerOrgCodeOrId '{"org_id":"80393"}'
GoSungrow api raw getInstallerInfoByDealerOrgCodeOrId '{"org_id":"300977"}'
-
GoSungrow api raw getKpiInfo
GoSungrow api raw getInstallInfoList
GoSungrow api raw getIncomeSettingInfos '{"ps_id":"1171348"}'
@@ -118,43 +116,22 @@ GoSungrow api raw getOrgListForUser
GoSungrow api raw getPowerDevicePointNames '{"device_type":"1"}'
GoSungrow api raw getPowerDeviceModelTechList '{"device_type":"1"}'
GoSungrow api raw getPowerDevicePointInfo '{"id":"1"}'
-GoSungrow api raw getPowerStationForHousehold '{"ps_id":"1171348"}'
-
GoSungrow api raw queryPsProfit '{"date_id":"20221001","date_type":"1","ps_id":"1171348"}'
GoSungrow api raw getPowerStationData '{"date_id":"20221001","date_type":"1","ps_id":"1171348"}'
GoSungrow api get getHouseholdStoragePsReport '{"date_id":"20221001","date_type":"1","ps_id":"1171348"}'
-
GoSungrow api raw queryPsProfit '{"date_id":"202210","date_type":"2","ps_id":"1171348"}'
GoSungrow api raw getPowerStationData '{"date_id":"202210","date_type":"2","ps_id":"1171348"}'
GoSungrow api get getHouseholdStoragePsReport '{"date_id":"202210","date_type":"2","ps_id":"1171348"}'
-
GoSungrow api raw queryPsProfit '{"date_id":"2022","date_type":"3","ps_id":"1171348"}'
GoSungrow api raw getPowerStationData '{"date_id":"2022","date_type":"3","ps_id":"1171348"}'
GoSungrow api get getHouseholdStoragePsReport '{"date_id":"2022","date_type":"3","ps_id":"1171348"}'
-
GoSungrow api raw getPowerStationInfo '{"ps_id":"1171348"}'
GoSungrow api raw getPowerTrendDayData '{"BeginTime":"20221004"}'
GoSungrow api raw getPowerSettingCharges
GoSungrow api raw queryUnitList
GoSungrow api raw queryPsIdList
GoSungrow api get getEncryptPublicKey
-
GoSungrow api raw getFaultCount
GoSungrow api raw getFaultDetail '{"fault_code":"34"}'
GoSungrow api raw getFaultMsgByFaultCode '{"fault_code":"703"}'
GoSungrow api get getFaultMsgListWithYYYYMM
-
-
-################################################################################
-
-"energy_flow"
-1 / 3 - PV2Load && PV2Battery
-
-
- "1" - PV to Load
- "3" - Battery to Load
- "5" - PV to Battery
-
-https://augateway.isolarcloud.com/v1/commonService/getMqttConfigInfoByAppkey
-sensor.sungrow_total_load_active_power == sensor.sungrow_total_active_power
-
diff --git a/google/const.go b/google/const.go
deleted file mode 100644
index 112c0ff87..000000000
--- a/google/const.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package google
-
-const (
- DefaultGoogleClientId = "424242424242-42424242424242424242424242424242.apps.googleusercontent.com"
- DefaultGoogleClientSecret = "424242424242424242424242"
- DefaultGoogleCredentials = `{"installed":{"client_id":"424242424242-42424242424242424242424242424242.apps.googleusercontent.com","project_id":"isolarcloud","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"424242424242424242424242","redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]}}
-`
- DefaultAuthTokenFile = "GoogleSheetsAuthToken.json"
-)
diff --git a/google/sheet.go b/google/sheet.go
deleted file mode 100644
index 7ed6dc333..000000000
--- a/google/sheet.go
+++ /dev/null
@@ -1,111 +0,0 @@
-package google
-
-import (
- "GoSungrow/Only"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "golang.org/x/oauth2"
- "net/http"
- "os"
-)
-
-// Retrieve a token, saves the token, then returns the generated client.
-func (s *Sheet) getClient() (*http.Client, error) {
- var ret *http.Client
- var err error
-
- for range Only.Once {
- // The file token.json stores the user's access and refresh tokens, and is
- // created automatically when the authorization flow completes for the first
- // time.
-
- var err error
- err = s.tokenFromFile()
- if err != nil {
- err = s.getTokenFromWeb()
- if err != nil {
- break
- }
- err = s.saveToken()
- if err != nil {
- break
- }
- }
-
- ret = s.oAuthConfig.Client(context.Background(), s.token)
- }
-
- return ret, err
-}
-
-// RequestCommon a token from the web, then returns the retrieved token.
-func (s *Sheet) getTokenFromWeb() error {
- var err error
-
- for range Only.Once {
- authURL := s.oAuthConfig.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
- fmt.Printf("Allow access to this application by going to this URL:\n%v\n", authURL)
- fmt.Printf("\nThen copy-paste the authorization code here: ")
-
- var authCode string
- _, err = fmt.Scan(&authCode)
- if err != nil {
- err = errors.New(fmt.Sprintf("Unable to read authorization code: %v", err))
- break
- }
-
- s.token, err = s.oAuthConfig.Exchange(context.TODO(), authCode)
- if err != nil {
- err = errors.New(fmt.Sprintf("Unable to retrieve token from web: %v", err))
- break
- }
- }
-
- return err
-}
-
-// Retrieves a token from a local file.
-func (s *Sheet) tokenFromFile() error {
- var err error
-
- for range Only.Once {
- if s.TokenFile == "" {
- err = errors.New("Empty token filename")
- break
- }
-
- var f *os.File
- f, err = os.Open(s.TokenFile)
- if err != nil {
- break
- }
-
- defer f.Close()
- //ret = &oauth2.token{}
- err = json.NewDecoder(f).Decode(s.token)
- }
-
- return err
-}
-
-// Saves a token to a file path.
-func (s *Sheet) saveToken() error {
- var err error
-
- for range Only.Once {
- fmt.Printf("Saving token file to: %s\n", s.TokenFile)
- var f *os.File
- f, err = os.OpenFile(s.TokenFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
- if err != nil {
- err = errors.New(fmt.Sprintf("Unable to cache oauth token: %v", err))
- break
- }
-
- defer f.Close()
- err = json.NewEncoder(f).Encode(s.token)
- }
-
- return err
-}
diff --git a/google/struct.go b/google/struct.go
deleted file mode 100644
index 02dcc2a1e..000000000
--- a/google/struct.go
+++ /dev/null
@@ -1,193 +0,0 @@
-package google
-
-import (
- "GoSungrow/Only"
- "context"
- "errors"
- "fmt"
- "golang.org/x/oauth2"
- "golang.org/x/oauth2/google"
- "google.golang.org/api/googleapi"
- "google.golang.org/api/option"
- "google.golang.org/api/sheets/v4"
- "net/http"
- "os"
- "path/filepath"
-)
-
-const DefaultId = "SUPERSECRETKEY"
-
-type Sheet struct {
- Id string
- SheetName string
- Range string
- Credentials []byte
- TokenFile string
- token *oauth2.Token
- oAuthConfig *oauth2.Config
-
- Data SheetData
-}
-type SheetData [][]interface{}
-
-func (s *Sheet) Set(cfg Sheet) {
- for range Only.Once {
- s.Id = cfg.Id
- s.SheetName = cfg.SheetName
- s.Range = cfg.Range
-
- s.Credentials = cfg.Credentials
- s.TokenFile = cfg.TokenFile
- s.token = cfg.token
-
- s.Verify()
- }
-}
-
-func (s *Sheet) Verify() bool {
- var ok bool
- for range Only.Once {
- if s.Id == "" {
- s.Id = DefaultId
- }
- if s.SheetName == "" {
- s.SheetName = ""
- }
- if s.Range == "" {
- s.Range = "A1"
- }
- if len(s.Credentials) == 0 {
- s.Credentials = []byte(DefaultGoogleCredentials)
- }
-
- // token *oauth2.token
- // oAuthConfig *oauth2.Config
-
- if s.oAuthConfig == nil {
- s.oAuthConfig = &oauth2.Config{}
- }
- if s.token == nil {
- s.token = &oauth2.Token{}
- }
-
- if len(s.TokenFile) == 0 {
- var err error
- s.TokenFile, err = os.UserHomeDir()
- if err != nil {
- s.TokenFile = ""
- break
- }
- s.TokenFile = filepath.Join(s.TokenFile, ".GoSungrow", DefaultAuthTokenFile)
- }
-
- ok = true
- }
-
- return ok
-}
-
-func (s *Sheet) ReadSheet() (SheetData, error) {
- var err error
- var csv SheetData
-
- for range Only.Once {
- if !s.Verify() {
- break
- }
-
- // If modifying these scopes, delete your previously saved token.json.
- s.oAuthConfig, err = google.ConfigFromJSON(s.Credentials, sheets.SpreadsheetsReadonlyScope)
- if err != nil {
- err = errors.New(fmt.Sprintf("Unable to parse client secret file to config: %v", err))
- break
- }
-
- var client *http.Client
- client, err = s.getClient()
-
- ctx := context.Background()
- var srv *sheets.Service
- srv, err = sheets.NewService(ctx, option.WithHTTPClient(client))
- if err != nil {
- err = errors.New(fmt.Sprintf("Unable to retrieve Sheets client: %v", err))
- break
- }
-
- readRange := fmt.Sprintf("%s!%s", s.SheetName, s.Range)
- var resp *sheets.ValueRange
- resp, err = srv.Spreadsheets.Values.Get(s.Id, readRange).Do()
- if err != nil {
- err = errors.New(fmt.Sprintf("Unable to retrieve data from sheet: %v", err))
- break
- }
-
- if len(resp.Values) == 0 {
- fmt.Println("No data found.")
- break
- }
-
- for _, row := range resp.Values {
- // Print columns A and E, which correspond to indices 0 and 4.
- fmt.Printf("%v\n", row)
- }
- }
-
- return csv, err
-}
-
-func (s *Sheet) WriteSheet() error {
- var err error
-
- for range Only.Once {
- if !s.Verify() {
- break
- }
-
- // If modifying these scopes, delete your previously saved token.json.
- s.oAuthConfig, err = google.ConfigFromJSON(s.Credentials, sheets.SpreadsheetsScope)
- if err != nil {
- err = errors.New(fmt.Sprintf("Unable to parse client secret file to config: %v", err))
- break
- }
-
- var client *http.Client
- client, err = s.getClient()
- //client = getClient(s.oAuthConfig)
-
- ctx := context.Background()
- var srv *sheets.Service
- srv, err = sheets.NewService(ctx, option.WithHTTPClient(client))
- if err != nil {
- err = errors.New(fmt.Sprintf("Unable to retrieve Sheets client: %v", err))
- break
- }
-
- //var itt = srv.Spreadsheets.getSheetByName('_EmailList');
- //if (!itt) {
- // ss.insertSheet('_EmailList');
- //}
-
- vr := sheets.ValueRange{
- MajorDimension: "",
- Range: s.SheetName + "!" + s.Range,
- Values: s.Data,
- ServerResponse: googleapi.ServerResponse{},
- ForceSendFields: nil,
- NullFields: nil,
- }
-
- writeRange := fmt.Sprintf("%s!%s", s.SheetName, s.Range)
- fmt.Printf("Updating Google sheet '%s'.\n\tWorksheet: %s\n\tStarting from: %s\n",
- s.Id,
- s.SheetName,
- s.Range,
- )
- _, err = srv.Spreadsheets.Values.Update(s.Id, writeRange, &vr).ValueInputOption("USER_ENTERED").Do() // or "RAW"
- if err != nil {
- err = errors.New(fmt.Sprintf("Unable to retrieve data from sheet. %v", err))
- break
- }
- }
-
- return err
-}
diff --git a/iSolarCloud/AppService/getDeviceList/data.go b/iSolarCloud/AppService/getDeviceList/data.go
index fa72ee9b6..854ae866a 100644
--- a/iSolarCloud/AppService/getDeviceList/data.go
+++ b/iSolarCloud/AppService/getDeviceList/data.go
@@ -11,7 +11,7 @@ const Url = "/v1/devService/getDeviceList"
const Disabled = false
type RequestData struct {
- PsId int64 `json:"ps_id" required:"true"`
+ PsId string `json:"ps_id" required:"true"`
}
func (rd RequestData) IsValid() error {
@@ -26,7 +26,7 @@ func (rd RequestData) Help() string {
type ResultData struct {
PageList []struct {
AttrID int64 `json:"attr_id"`
- ChnnlID int64 `json:"chnnl_id"`
+ ChannelId int64 `json:"chnnl_id"`
CommandStatus int64 `json:"command_status"`
ConnectState int64 `json:"connect_state"`
DataFlag int64 `json:"data_flag"`
@@ -132,7 +132,7 @@ func (e *EndPoint) GetDataTable() output.Table {
d.PsID,
d.DeviceType,
d.DeviceCode,
- d.ChnnlID,
+ d.ChannelId,
d.TypeName,
d.DeviceProSn,
d.DeviceModel,
diff --git a/iSolarCloud/AppService/queryPsProfit/data.go b/iSolarCloud/AppService/queryPsProfit/data.go
index bfbef6565..98712e11d 100644
--- a/iSolarCloud/AppService/queryPsProfit/data.go
+++ b/iSolarCloud/AppService/queryPsProfit/data.go
@@ -41,15 +41,15 @@ type ResultData struct {
CuspPowerQuantity interface{} `json:"cusp_power_quantity"`
CuspUsePowerQuantity interface{} `json:"cusp_use_power_quantity"`
DateID int64 `json:"date_id"`
- FlatNetPowerQuantity int64 `json:"flat_net_power_quantity"`
- FlatPowerQuantity int64 `json:"flat_power_quantity"`
+ FlatNetPowerQuantity float64 `json:"flat_net_power_quantity"`
+ FlatPowerQuantity float64 `json:"flat_power_quantity"`
FlatUsePowerQuantity float64 `json:"flat_use_power_quantity"`
NetPowerProfit float64 `json:"net_power_profit"`
- NetPowerQuantityTotal int64 `json:"net_power_quantity_total"`
+ NetPowerQuantityTotal float64 `json:"net_power_quantity_total"`
PeakNetPowerQuantity interface{} `json:"peak_net_power_quantity"`
PeakPowerQuantity interface{} `json:"peak_power_quantity"`
PeakUsePowerQuantity interface{} `json:"peak_use_power_quantity"`
- PowerQuantityTotal int64 `json:"power_quantity_total"`
+ PowerQuantityTotal float64 `json:"power_quantity_total"`
SubsidyProfit interface{} `json:"subsidy_profit"`
TotalProfit float64 `json:"total_profit"`
UpdateTime string `json:"update_time"`
diff --git a/iSolarCloud/AppService/reportList/data.go b/iSolarCloud/AppService/reportList/data.go
index 05b729281..42c24455f 100644
--- a/iSolarCloud/AppService/reportList/data.go
+++ b/iSolarCloud/AppService/reportList/data.go
@@ -97,7 +97,7 @@ type ResultData struct {
SubsidyProfitOriginalUnit string `json:"subsidy_profit_original_unit"`
SubsidyProfitTran string `json:"subsidy_profit_tran"`
SubsidyProfitUnit string `json:"subsidy_profit_unit"`
- TimeStamp string `json:"time_stamp"`
+ TimeStamp interface{} `json:"time_stamp"` // Sad that this alternates between string and int64.
TotalProfit string `json:"total_profit"`
TotalProfitOriginalUnit string `json:"total_profit_original_unit"`
TotalProfitTran string `json:"total_profit_tran"`
diff --git a/iSolarCloud/highlevel.go b/iSolarCloud/highlevel.go
index 2a35b4d45..6b52faac8 100644
--- a/iSolarCloud/highlevel.go
+++ b/iSolarCloud/highlevel.go
@@ -113,8 +113,8 @@ func (sg *SunGrow) GetTemplateData(template string, date string, filter string)
break
}
- table.SetTitle("Template %s on %s for %s", template, when.String(), psId)
- table.SetFilePrefix(data.SetFilenamePrefix("%s-%s-%s", when.String(), template, psId))
+ table.SetTitle("Template %s on %s for %d", template, when.String(), psId)
+ table.SetFilePrefix(data.SetFilenamePrefix("%s-%s-%d", when.String(), template, psId))
table.SetGraphFilter(filter)
table.SetSaveFile(sg.SaveAsFile)
table.OutputType = sg.OutputType
@@ -694,7 +694,7 @@ func (sg *SunGrow) GetDevices(psIds ...int64) error {
for _, psId := range psIds {
ep := sg.GetByStruct(
"AppService.getDeviceList",
- getDeviceList.RequestData{PsId: psId},
+ getDeviceList.RequestData{PsId: strconv.FormatInt(psId, 10)},
DefaultCacheTimeout,
)
if sg.Error != nil {
diff --git a/lsgo/arguments.go b/lsgo/arguments.go
deleted file mode 100644
index 322c51450..000000000
--- a/lsgo/arguments.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package lsgo
-
-import (
- "log"
-
- kingpin "gopkg.in/alecthomas/kingpin.v2"
-)
-
-// declare the struct that holds all the arguments
-type arguments struct {
- paths *[]string
- all *bool
- bytes *bool
- mdate *bool
- owner *bool
- nogroup *bool
- perms *bool
- long *bool
- dirs *bool
- files *bool
- links *bool
- linkRel *bool
- sortSize *bool
- sortTime *bool
- sortKind *bool
- backwards *bool
- stats *bool
- icons *bool
- nerdfont *bool
- recurse *bool
- find *string
-}
-
-var args = arguments{
- kingpin.Arg("paths", "the files(s) and/or folder(s) to display").Default(".").Strings(),
- kingpin.Flag("all", "show hidden files").Short('a').Bool(),
- kingpin.Flag("bytes", "include size").Short('b').Bool(),
- kingpin.Flag("mdate", "include modification date").Short('m').Bool(),
- kingpin.Flag("owner", "include owner and group").Short('o').Bool(),
- kingpin.Flag("nogroup", "hide group").Short('N').Bool(),
- kingpin.Flag("perms", "include permissions for owner, group, and other").Short('p').Bool(),
- kingpin.Flag("long", "include size, date, owner, and permissions").Short('l').Bool(),
- kingpin.Flag("dirs", "only show directories").Short('d').Bool(),
- kingpin.Flag("files", "only show files").Short('f').Bool(),
- kingpin.Flag("links", "show paths for symlinks").Short('L').Bool(),
- kingpin.Flag("link-rel", "show symlinks as relative paths if shorter than absolute path").Short('R').Bool(),
- kingpin.Flag("size", "sort items by size").Short('s').Bool(),
- kingpin.Flag("time", "sort items by time").Short('t').Bool(),
- kingpin.Flag("kind", "sort items by extension").Short('k').Bool(),
- kingpin.Flag("backwards", "reverse the sort order of --size, --time, or --kind").Short('B').Bool(),
- kingpin.Flag("stats", "show statistics").Short('S').Bool(),
- kingpin.Flag("icons", "show folder icon before dirs").Short('i').Bool(),
- kingpin.Flag("nerd-font", "show nerd font glyphs before file names").Short('n').Bool(),
- kingpin.Flag("recurse", "traverse all dirs recursively").Short('r').Bool(),
- kingpin.Flag("find", "filter items with a regexp").Short('F').String(),
-}
-
-func argsPostParse() {
- if *args.long {
- args.bytes = &True
- args.mdate = &True
- args.owner = &True
- args.perms = &True
- args.links = &True
- }
- if *args.dirs && *args.files {
- log.Fatal("--dirs and --files cannot both be set")
- }
- if *args.nerdfont && *args.icons {
- log.Fatal("--nerd-font and --icons cannot both be set")
- }
-}
diff --git a/lsgo/colors.go b/lsgo/colors.go
deleted file mode 100644
index 50841ed42..000000000
--- a/lsgo/colors.go
+++ /dev/null
@@ -1,351 +0,0 @@
-package lsgo
-
-import (
- "fmt"
- "strconv"
- "strings"
-)
-
-// see the color codes
-// http://i.stack.imgur.com/UQVe5.png
-
-// Fg wraps an 8-bit foreground color code in the ANSI escape sequence
-func Fg(code int) string {
- colored := []string{"\x1b[38;5;", strconv.Itoa(code), "m"}
- return strings.Join(colored, "")
-}
-
-// Bg wraps an 8-bit background color code in the ANSI escape sequence
-func Bg(code int) string {
- colored := []string{"\x1b[48;5;", strconv.Itoa(code), "m"}
- return strings.Join(colored, "")
-}
-
-// Rgb2code converts RGB values (up to 5) to an 8-bit color code
-func Rgb2code(r int, g int, b int) int {
- code := 36*r + 6*g + b + 16
- if code < 16 || 231 < code {
- panic(fmt.Errorf("Invalid RGB values (%d, %d, %d)", r, g, b))
- }
- return code
-}
-
-// Gray2code converts a scalar of "grayness" to an 8-bit color code
-func Gray2code(lightness int) int {
- code := lightness + 232
- if code < 232 || 255 < code {
- panic(fmt.Errorf("Invalid lightness value (%d) for gray", lightness))
- }
- return code
-}
-
-// FgRGB converts RGB values (up to 5) to an ANSI-escaped foreground 8-bit color code
-func FgRGB(r int, g int, b int) string {
- return Fg(Rgb2code(r, g, b))
-}
-
-// BgRGB converts RGB values (up to 5) to an ANSI-escaped background 8-bit color code
-func BgRGB(r int, g int, b int) string {
- return Bg(Rgb2code(r, g, b))
-}
-
-// FgGray converts a scalar of "grayness" to an ANSI-escaped foreground 8-bit color code
-func FgGray(lightness int) string {
- return Fg(Gray2code(lightness))
-}
-
-// BgGray converts a scalar of "grayness" to an ANSI-escaped background 8-bit color code
-func BgGray(lightness int) string {
- return Bg(Gray2code(lightness))
-}
-
-const (
- // Reset undoes ANSI color codes
- Reset = "\x1b[0m"
- // Bold makes text bold
- Bold = "\x1b[1m"
-)
-
-var (
- // FileColor is a mapping of filetypes to colors
- FileColor = map[string][2]string{
- "as": [2]string{Fg(196), Fg(124)},
- "asm": [2]string{Fg(223), Fg(215)},
- "bf": [2]string{Fg(223), Fg(215)},
- "c": [2]string{Fg(39), Fg(27)},
- "clj": [2]string{Fg(204), Fg(162)},
- "coffee": [2]string{Fg(136), Fg(94)},
- "cr": [2]string{Fg(82), Fg(70)},
- "cson": [2]string{Fg(136), Fg(94)},
- "css": [2]string{Fg(219), Fg(207)},
- "dart": [2]string{Fg(43), Fg(31)},
- "diff": [2]string{Fg(10), Fg(9)},
- "elm": [2]string{Fg(51), Fg(39)},
- "erl": [2]string{Fg(161), Fg(89)},
- "ex": [2]string{Fg(99), Fg(57)},
- "f": [2]string{Fg(208), Fg(94)},
- "fs": [2]string{Fg(45), Fg(32)},
- "gb": [2]string{Fg(43), Fg(29)},
- "go": [2]string{Fg(121), Fg(109)},
- "graphql": [2]string{Fg(219), Fg(207)},
- "groovy": [2]string{Fg(223), Fg(215)},
- "gv": [2]string{Fg(141), Fg(99)},
- "hs": [2]string{Fg(99), Fg(57)},
- "html": [2]string{Fg(87), Fg(73)},
- "ino": [2]string{Fg(43), Fg(29)},
- "java": [2]string{Fg(136), Fg(94)},
- "jl": [2]string{Fg(141), Fg(99)},
- "js": [2]string{FgRGB(4, 4, 0), FgRGB(2, 2, 0)},
- "jsx": [2]string{Fg(87), Fg(73)},
- "lock": [2]string{FgGray(8), FgGray(5)},
- "log": [2]string{FgGray(8), FgGray(5)},
- "lua": [2]string{Fg(39), Fg(27)},
- "m": [2]string{Fg(208), Fg(196)},
- "md": [2]string{Fg(87), Fg(73)},
- "ml": [2]string{Fg(208), Fg(94)},
- "php": [2]string{Fg(30), Fg(22)},
- "pl": [2]string{Fg(99), Fg(57)},
- "py": [2]string{Fg(34), Fg(28)},
- "r": [2]string{Fg(51), Fg(39)},
- "rb": [2]string{FgRGB(5, 1, 0), FgRGB(3, 1, 1)},
- "rs": [2]string{Fg(208), Fg(94)},
- "scala": [2]string{Fg(196), Fg(124)},
- "sh": [2]string{FgRGB(4, 0, 4), FgRGB(2, 0, 2)},
- "sol": [2]string{Fg(39), Fg(27)},
- "sql": [2]string{Fg(193), Fg(148)},
- "svelte": [2]string{Fg(208), Fg(196)},
- "swift": [2]string{Fg(223), Fg(215)},
- "vim": [2]string{Fg(34), Fg(28)},
- "vue": [2]string{Fg(43), Fg(29)},
- "xml": [2]string{Fg(87), Fg(73)},
-
- "compiled": [2]string{FgGray(8), FgGray(5)},
- "compress": [2]string{FgRGB(5, 0, 0), FgRGB(3, 0, 0)},
- "document": [2]string{FgRGB(5, 0, 0), FgRGB(3, 0, 0)},
- "media": [2]string{Fg(141), Fg(99)},
- "_default": [2]string{FgGray(23), FgGray(12)},
- }
- // FileAliases converts alternative extensions to their canonical mapping in FileColor
- FileAliases = map[string]string{
- "s": "asm",
- "b": "bf",
- "c++": "c",
- "cc": "c",
- "cpp": "c",
- "cs": "c",
- "cxx": "c",
- "d": "c",
- "h": "c",
- "h++": "c",
- "hh": "c",
- "hpp": "c",
- "hxx": "c",
- "pxd": "c",
- "cljc": "clj",
- "cljs": "clj",
- "class": "compiled",
- "elc": "compiled",
- "hi": "compiled",
- "o": "compiled",
- "pyc": "compiled",
- "7z": "compress",
- "Z": "compress",
- "bz2": "compress",
- "deb": "compress",
- "dmg": "compress",
- "dpkg": "compress",
- "gz": "compress",
- "iso": "compress",
- "jar": "compress",
- "lzma": "compress",
- "par": "compress",
- "rar": "compress",
- "rpm": "compress",
- "tar": "compress",
- "tc": "compress",
- "tgz": "compress",
- "txz": "compress",
- "whl": "compress",
- "xz": "compress",
- "z": "compress",
- "zip": "compress",
- "less": "css",
- "sass": "css",
- "scss": "css",
- "styl": "css",
- "djvu": "document",
- "doc": "document",
- "docx": "document",
- "dvi": "document",
- "eml": "document",
- "fotd": "document",
- "odp": "document",
- "odt": "document",
- "pdf": "document",
- "ppt": "document",
- "pptx": "document",
- "rtf": "document",
- "xls": "document",
- "xlsx": "document",
- "f03": "f",
- "f77": "f",
- "f90": "f",
- "f95": "f",
- "for": "f",
- "fpp": "f",
- "ftn": "f",
- "fsi": "fs",
- "fsscript": "fs",
- "fsx": "fs",
- "dna": "gb",
- "gsh": "groovy",
- "gvy": "groovy",
- "gy": "groovy",
- "htm": "html",
- "xhtml": "html",
- "bson": "js",
- "json": "js",
- "mjs": "js",
- "ts": "js",
- "tsx": "jsx",
- "cjsx": "jsx",
- "mat": "m",
- "markdown": "md",
- "mkd": "md",
- "rst": "md",
- "sml": "ml",
- "mli": "ml",
- "aac": "media",
- "alac": "media",
- "audio": "media",
- "avi": "media",
- "bmp": "media",
- "cbr": "media",
- "cbz": "media",
- "eps": "media",
- "flac": "media",
- "flv": "media",
- "gif": "media",
- "ico": "media",
- "image": "media",
- "jpeg": "media",
- "jpg": "media",
- "m2v": "media",
- "m4a": "media",
- "mka": "media",
- "mkv": "media",
- "mov": "media",
- "mp3": "media",
- "mp4": "media",
- "mpeg": "media",
- "mpg": "media",
- "nef": "media",
- "ogg": "media",
- "ogm": "media",
- "ogv": "media",
- "opus": "media",
- "orf": "media",
- "pbm": "media",
- "pgm": "media",
- "png": "media",
- "pnm": "media",
- "ppm": "media",
- "pxm": "media",
- "stl": "media",
- "svg": "media",
- "tif": "media",
- "tiff": "media",
- "video": "media",
- "vob": "media",
- "wav": "media",
- "webm": "media",
- "webp": "media",
- "wma": "media",
- "wmv": "media",
- "xpm": "media",
- "php3": "php",
- "php4": "php",
- "php5": "php",
- "phpt": "php",
- "phtml": "php",
- "ipynb": "py",
- "pickle": "py",
- "pkl": "py",
- "pyx": "py",
- "bash": "sh",
- "csh": "sh",
- "fish": "sh",
- "ksh": "sh",
- "zsh": "sh",
- "plpgsql": "sql",
- "plsql": "sql",
- "psql": "sql",
- "tsql": "sql",
- "vimrc": "vim",
- }
- // SizeColor has the color mappings for ranges of file sizes
- SizeColor = map[string]string{
- "B": Fg(27),
- "K": Fg(33),
- "M": Fg(81),
- "G": Fg(123),
- "T": Fg(159),
- }
- // ConfigColor holds mappings for other various colors
- ConfigColor = map[string]map[string]string{
- "dir": map[string]string{
- "name": Bold + BgRGB(0, 0, 2) + FgGray(23),
- "ext": FgRGB(2, 2, 5),
- },
- ".dir": map[string]string{
- "name": Bold + BgRGB(0, 0, 1) + FgGray(23),
- "ext": FgRGB(2, 2, 5),
- },
- "folderHeader": map[string]string{
- "arrow": FgRGB(3, 2, 0),
- "main": BgGray(2) + FgRGB(3, 2, 0),
- "slash": FgGray(5),
- "lastFolder": Bold + FgRGB(5, 5, 0),
- "error": BgRGB(5, 0, 0) + FgRGB(5, 5, 0),
- },
- "link": map[string]string{
- "name": Bold + FgRGB(0, 5, 0),
- "nameDir": Bold + BgRGB(0, 0, 2) + FgRGB(0, 5, 5),
- "arrow": FgRGB(1, 0, 1),
- "path": FgRGB(4, 0, 4),
- "broken": FgRGB(5, 0, 0),
- },
- "device": map[string]string{
- "name": Bold + BgGray(3) + Fg(220),
- },
- "socket": map[string]string{
- "name": Bold + Bg(53) + Fg(15),
- },
- "pipe": map[string]string{
- "name": Bold + Bg(94) + Fg(15),
- },
- "stats": map[string]string{
- "text": BgGray(2) + FgGray(15),
- "number": Fg(24),
- "ms": Fg(39),
- },
- }
- // PermsColor holds color mappings for users and groups
- PermsColor = map[string]map[string]string{
- "user": map[string]string{
- "root": FgRGB(5, 0, 2),
- "daemon": FgRGB(4, 2, 1),
- "_self": FgRGB(0, 4, 0),
- "_default": FgRGB(0, 3, 3),
- },
- "group": map[string]string{
- "wheel": FgRGB(3, 0, 0),
- "staff": FgRGB(0, 2, 0),
- "admin": FgRGB(2, 2, 0),
- "_default": FgRGB(2, 0, 2),
- },
- "other": map[string]string{
- "_default": BgGray(2) + FgGray(15),
- },
- }
-)
diff --git a/lsgo/file-icons.go b/lsgo/file-icons.go
deleted file mode 100644
index 39f90b080..000000000
--- a/lsgo/file-icons.go
+++ /dev/null
@@ -1,402 +0,0 @@
-package lsgo
-
-import (
- "strings"
-)
-
-func getIconForFile(name, ext string) string {
- // default icon for all files. try to find a better one though...
- icon := icons["file"]
-
- // resolve aliased extensions
- extKey := strings.ToLower(ext)
- alias, hasAlias := aliases[extKey]
- if hasAlias {
- extKey = alias
- }
-
- // see if we can find a better icon based on extension alone
- betterIcon, hasBetterIcon := icons[extKey]
- if hasBetterIcon {
- icon = betterIcon
- }
-
- // now look for icons based on full names
- fullName := name
- if ext != "" {
- fullName += "." + ext
- }
-
- fullName = strings.ToLower(fullName)
- fullAlias, hasFullAlias := aliases[fullName]
- if hasFullAlias {
- fullName = fullAlias
- }
- bestIcon, hasBestIcon := icons[fullName]
- if hasBestIcon {
- icon = bestIcon
- }
- return icon
-}
-
-func getIconForFolder(name string) string {
- icon := folders["folder"]
- betterIcon, hasBetterIcon := folders[name]
- if hasBetterIcon {
- icon = betterIcon
- }
- return icon
-}
-
-var icons = map[string]string{
- "ai": "\ue7b4",
- "android": "\ue70e",
- "apple": "\uf179",
- "as": "\ue60b",
- "asm": "\ufb19",
- "audio": "\uf1c7",
- "avro": "\ue60b",
- "bf": "\uf067",
- "binary": "\uf471",
- "c": "\ue61e",
- "cargo.lock": "\uf487",
- "cargo.toml": "\uf487",
- "cfg": "\uf423",
- "clj": "\ue768",
- "coffee": "\ue751",
- "conf": "\ue615",
- "cpp": "\ue61d",
- "cr": "\ue23e",
- "cs": "\uf81a",
- "cson": "\ue601",
- "css": "\ue749",
- "d": "\ue7af",
- "dart": "\ue798",
- "db": "\uf1c0",
- "deb": "\uf306",
- "diff": "\uf440",
- "doc": "\uf1c2",
- "dockerfile": "\ue7b0",
- "dpkg": "\uf17c",
- "ebook": "\uf02d",
- "elm": "\ue62c",
- "env": "\uf462",
- "erl": "\ue7b1",
- "ex": "\ue62d",
- "f": "\uf794",
- "file": "\uf15b",
- "font": "\uf031",
- "fs": "\ue7a7",
- "gb": "\ue272",
- "gform": "\uf298",
- "git": "\ue702",
- "go": "\ue724",
- "graphql": "\ue284",
- "groovy": "\ue775",
- "gruntfile.js": "\ue74c",
- "gulpfile.js": "\ue610",
- "gv": "\ue225",
- "h": "\uf0fd",
- "hs": "\ue777",
- "html": "\uf13b",
- "ics": "\uf073",
- "image": "\uf1c5",
- "iml": "\ue7b5",
- "ini": "\uf669",
- "ino": "\ue255",
- "iso": "\uf7c9",
- "java": "\ue738",
- "jenkinsfile": "\ue767",
- "jl": "\ue624",
- "js": "\ue781",
- "json": "\ue60b",
- "jsx": "\ue7ba",
- "key": "\uf43d",
- "less": "\ue758",
- "lock": "\uf720",
- "log": "\uf18d",
- "lua": "\ue620",
- "m": "\ufb27",
- "maintainers": "\uf0c0",
- "makefile": "\ue20f",
- "md": "\uf48a",
- "mjs": "\ue718",
- "ml": "\ufb26",
- "mustache": "\ue60f",
- "nc": "\uf7c0",
- "npmignore": "\ue71e",
- "passwd": "\uf023",
- "patch": "\uf440",
- "pdf": "\uf1c1",
- "php": "\ue608",
- "pl": "\ue7a1",
- "ppt": "\uf1c4",
- "psd": "\ue7b8",
- "py": "\ue606",
- "r": "\ufcd2",
- "rb": "\ue21e",
- "rdb": "\ue76d",
- "rpm": "\uf17c",
- "rs": "\ue7a8",
- "rss": "\uf09e",
- "rst": "\uf66a",
- "rubydoc": "\ue73b",
- "sass": "\ue603",
- "scala": "\ue737",
- "shell": "\uf489",
- "shp": "\ufa5f",
- "sol": "\ufcb9",
- "sql": "\ue706",
- "sqlite3": "\ue7c4",
- "styl": "\ue600",
- "swift": "\ue755",
- "tex": "\u222b",
- "tfrecord": "\ufb27",
- "toml": "\uf669",
- "ts": "\ufbe4",
- "twig": "\ue61c",
- "txt": "\uf15c",
- "vagrantfile": "\ue21e",
- "video": "\uf03d",
- "vim": "\ue62b",
- "vue": "\ufd42",
- "windows": "\uf17a",
- "xls": "\uf1c3",
- "xml": "\ue796",
- "yml": "\ue601",
- "zip": "\uf410",
-}
-
-var aliases = map[string]string{
- "apk": "android",
- "gradle": "android",
- "ds_store": "apple",
- "localized": "apple",
- "s": "asm",
- "aac": "audio",
- "alac": "audio",
- "flac": "audio",
- "m4a": "audio",
- "mka": "audio",
- "mp3": "audio",
- "ogg": "audio",
- "opus": "audio",
- "wav": "audio",
- "wma": "audio",
- "b": "bf",
- "bson": "binary",
- "feather": "binary",
- "mat": "binary",
- "o": "binary",
- "pb": "binary",
- "pickle": "binary",
- "pkl": "binary",
- "conf": "cfg",
- "config": "cfg",
- "cljc": "clj",
- "cljs": "clj",
- "editorconfig": "conf",
- "rc": "conf",
- "c++": "cpp",
- "cc": "cpp",
- "cxx": "cpp",
- "scss": "css",
- "docx": "doc",
- "gdoc": "doc",
- "epub": "ebook",
- "ipynb": "ebook",
- "mobi": "ebook",
- "f03": "f",
- "f77": "f",
- "f90": "f",
- "f95": "f",
- "for": "f",
- "fpp": "f",
- "ftn": "f",
- "eot": "font",
- "otf": "font",
- "ttf": "font",
- "woff": "font",
- "woff2": "font",
- "fsi": "fs",
- "fsscript": "fs",
- "fsx": "fs",
- "dna": "gb",
- "gitattributes": "git",
- "gitconfig": "git",
- "gitignore": "git",
- "gitignore_global": "git",
- "gitmirrorall": "git",
- "gitmodules": "git",
- "gsh": "groovy",
- "gvy": "groovy",
- "gy": "groovy",
- "h++": "h",
- "hh": "h",
- "hpp": "h",
- "hxx": "h",
- "lhs": "hs",
- "htm": "html",
- "xhtml": "html",
- "bmp": "image",
- "cbr": "image",
- "cbz": "image",
- "dvi": "image",
- "eps": "image",
- "gif": "image",
- "ico": "image",
- "jpeg": "image",
- "jpg": "image",
- "nef": "image",
- "orf": "image",
- "pbm": "image",
- "pgm": "image",
- "png": "image",
- "pnm": "image",
- "ppm": "image",
- "pxm": "image",
- "stl": "image",
- "svg": "image",
- "tif": "image",
- "tiff": "image",
- "webp": "image",
- "xpm": "image",
- "disk": "iso",
- "dmg": "iso",
- "smi": "iso",
- "img": "iso",
- "vhd": "iso",
- "vhdx": "iso",
- "vmdk": "iso",
- "jar": "java",
- "properties": "json",
- "webmanifest": "json",
- "tsx": "jsx",
- "cjsx": "jsx",
- "cer": "key",
- "crt": "key",
- "der": "key",
- "gpg": "key",
- "p7b": "key",
- "pem": "key",
- "pfx": "key",
- "pgp": "key",
- "license": "key",
- "codeowners": "maintainers",
- "credits": "maintainers",
- "cmake": "makefile",
- "markdown": "md",
- "mkd": "md",
- "rdoc": "md",
- "readme": "md",
- "mli": "ml",
- "sml": "ml",
- "netcdf": "nc",
- "php3": "php",
- "php4": "php",
- "php5": "php",
- "phpt": "php",
- "phtml": "php",
- "gslides": "ppt",
- "pptx": "ppt",
- "pxd": "py",
- "pyc": "py",
- "pyx": "py",
- "whl": "py",
- "rdata": "r",
- "rds": "r",
- "rmd": "r",
- "gemfile": "rb",
- "gemspec": "rb",
- "guardfile": "rb",
- "procfile": "rb",
- "rakefile": "rb",
- "rspec": "rb",
- "rspec_parallel": "rb",
- "rspec_status": "rb",
- "ru": "rb",
- "erb": "rubydoc",
- "slim": "rubydoc",
- "awk": "shell",
- "bash": "shell",
- "bash_history": "shell",
- "bash_profile": "shell",
- "bashrc": "shell",
- "csh": "shell",
- "fish": "shell",
- "ksh": "shell",
- "sh": "shell",
- "zsh": "shell",
- "zsh-theme": "shell",
- "zshrc": "shell",
- "plpgsql": "sql",
- "plsql": "sql",
- "psql": "sql",
- "tsql": "sql",
- "sl3": "sqlite3",
- "stylus": "styl",
- "cls": "tex",
- "avi": "video",
- "flv": "video",
- "m2v": "video",
- "mkv": "video",
- "mov": "video",
- "mp4": "video",
- "mpeg": "video",
- "mpg": "video",
- "ogm": "video",
- "ogv": "video",
- "vob": "video",
- "webm": "video",
- "vimrc": "vim",
- "bat": "windows",
- "cmd": "windows",
- "exe": "windows",
- "csv": "xls",
- "gsheet": "xls",
- "xlsx": "xls",
- "svelte": "xml",
- "plist": "xml",
- "xul": "xml",
- "yaml": "yml",
- "7z": "zip",
- "Z": "zip",
- "bz2": "zip",
- "gz": "zip",
- "lzma": "zip",
- "par": "zip",
- "rar": "zip",
- "tar": "zip",
- "tc": "zip",
- "tgz": "zip",
- "txz": "zip",
- "xz": "zip",
- "z": "zip",
-}
-
-var folders = map[string]string{
- ".atom": "\ue764",
- ".aws": "\ue7ad",
- ".docker": "\ue7b0",
- ".gem": "\ue21e",
- ".git": "\ue5fb",
- ".git-credential-cache": "\ue5fb",
- ".github": "\ue5fd",
- ".npm": "\ue5fa",
- ".nvm": "\ue718",
- ".rvm": "\ue21e",
- ".Trash": "\uf1f8",
- ".vscode": "\ue70c",
- ".vim": "\ue62b",
- "config": "\ue5fc",
- "folder": "\uf07c",
- "hidden": "\uf023",
- "node_modules": "\ue5fa",
-}
-
-var otherIcons = map[string]string{
- "link": "\uf0c1",
- "linkDir": "\uf0c1",
- "brokenLink": "\uf127",
- "device": "\uf0a0",
-}
diff --git a/lsgo/img/demo-1.png b/lsgo/img/demo-1.png
deleted file mode 100644
index 14d3bdd60..000000000
Binary files a/lsgo/img/demo-1.png and /dev/null differ
diff --git a/lsgo/img/demo-2.png b/lsgo/img/demo-2.png
deleted file mode 100644
index da4864dda..000000000
Binary files a/lsgo/img/demo-2.png and /dev/null differ
diff --git a/lsgo/img/demo-3.png b/lsgo/img/demo-3.png
deleted file mode 100644
index 0637e1cb4..000000000
Binary files a/lsgo/img/demo-3.png and /dev/null differ
diff --git a/lsgo/img/demo-4.png b/lsgo/img/demo-4.png
deleted file mode 100644
index 5799e5e97..000000000
Binary files a/lsgo/img/demo-4.png and /dev/null differ
diff --git a/lsgo/img/demo-5.png b/lsgo/img/demo-5.png
deleted file mode 100644
index 102e69aaa..000000000
Binary files a/lsgo/img/demo-5.png and /dev/null differ
diff --git a/lsgo/img/ls-go.png b/lsgo/img/ls-go.png
deleted file mode 100644
index e469212d4..000000000
Binary files a/lsgo/img/ls-go.png and /dev/null differ
diff --git a/lsgo/ls-unix.go b/lsgo/ls-unix.go
deleted file mode 100644
index b98ee643f..000000000
--- a/lsgo/ls-unix.go
+++ /dev/null
@@ -1,46 +0,0 @@
-// +build !windows
-
-package lsgo
-
-import (
- "fmt"
- "os"
- "os/user"
- "strconv"
- "strings"
- "syscall"
-
- "github.com/willf/pad"
- "golang.org/x/sys/unix"
-)
-
-func getOwnerAndGroup(fileInfo *os.FileInfo) (string, string) {
- statT := (*fileInfo).Sys().(*syscall.Stat_t)
- uid := fmt.Sprint(statT.Uid)
- gid := fmt.Sprint(statT.Gid)
- owner, err := user.LookupId(uid)
- var ownerName string
- if err == nil {
- ownerName = owner.Username
- } else {
- ownerName = uid
- }
-
- group, err := user.LookupGroupId(gid)
- var groupName string
- if err == nil {
- groupName = group.Name
- } else {
- groupName = gid
- }
- return ownerName, groupName
-}
-
-func deviceNumbers(absPath string) string {
- stat := syscall.Stat_t{}
- err := syscall.Stat(absPath, &stat)
- check(err)
- major := strconv.FormatInt(int64(unix.Major(uint64(stat.Rdev))), 10)
- minor := strconv.FormatInt(int64(unix.Minor(uint64(stat.Rdev))), 10)
- return pad.Left(strings.Join([]string{major, minor}, ","), 7, " ") + " " + Reset
-}
diff --git a/lsgo/ls-windows.go b/lsgo/ls-windows.go
deleted file mode 100644
index cab287f5b..000000000
--- a/lsgo/ls-windows.go
+++ /dev/null
@@ -1,65 +0,0 @@
-// +build windows
-
-package lsgo
-
-import (
- "os"
- "strconv"
- "strings"
- "syscall"
- "unsafe"
-
- "github.com/willf/pad"
- "golang.org/x/sys/windows"
-)
-
-var (
- libadvapi32 = syscall.NewLazyDLL("advapi32.dll")
- procGetFileSecurity = libadvapi32.NewProc("GetFileSecurityW")
- procGetSecurityDescriptorOwner = libadvapi32.NewProc("GetSecurityDescriptorOwner")
-)
-
-func getOwnerAndGroup(fileInfo *os.FileInfo) (string, string) {
- path := (*fileInfo).Name()
-
- var needed uint32
- procGetFileSecurity.Call(
- uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(path))),
- 0x00000001, /* OWNER_SECURITY_INFORMATION */
- 0,
- 0,
- uintptr(unsafe.Pointer(&needed)))
- buf := make([]byte, needed)
- r1, _, err := procGetFileSecurity.Call(
- uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(path))),
- 0x00000001, /* OWNER_SECURITY_INFORMATION */
- uintptr(unsafe.Pointer(&buf[0])),
- uintptr(needed),
- uintptr(unsafe.Pointer(&needed)))
- if r1 == 0 && err != nil {
- return "", ""
- }
- var ownerDefaulted uint32
- var sid *syscall.SID
- r1, _, err = procGetSecurityDescriptorOwner.Call(
- uintptr(unsafe.Pointer(&buf[0])),
- uintptr(unsafe.Pointer(&sid)),
- uintptr(unsafe.Pointer(&ownerDefaulted)))
- if r1 == 0 && err != nil {
- return "", ""
- }
- uid, gid, _, err := sid.LookupAccount("")
- if r1 == 0 && err != nil {
- return "", ""
- }
- return uid, gid
-}
-
-func deviceNumbers(absPath string) string {
- stat := syscall.Stat_t{}
- err := syscall.Stat(absPath, &stat)
- check(err)
- major := strconv.FormatInt(int64(windows.Major(uint64(stat.Rdev))), 10)
- minor := strconv.FormatInt(int64(windows.Minor(uint64(stat.Rdev))), 10)
- return pad.Left(strings.Join([]string{major, minor}, ","), 7, " ") + " " + Reset
-}
diff --git a/lsgo/lsgo.go b/lsgo/lsgo.go
deleted file mode 100644
index aee96430d..000000000
--- a/lsgo/lsgo.go
+++ /dev/null
@@ -1,650 +0,0 @@
-package lsgo
-
-import (
- "fmt"
- "io/ioutil"
- "math"
- "os"
- "path"
- "path/filepath"
- "regexp"
- "sort"
- "strconv"
- "strings"
- "time"
-
- "github.com/acarl005/textcol"
- colorable "github.com/mattn/go-colorable"
- "github.com/willf/pad"
- kingpin "gopkg.in/alecthomas/kingpin.v2"
-)
-
-// DisplayItem wraps the file stat info and string to be printed
-type DisplayItem struct {
- display string
- info os.FileInfo
- basename string
- ext string
- link *LinkInfo
-}
-
-// LinkInfo wraps link stat info and whether the link points to valid file
-type LinkInfo struct {
- path string
- info os.FileInfo
- broken bool
-}
-
-var (
- // True is a helper varable to help make pointers to `true`
- True = true
- sizeUnits = []string{"B", "K", "M", "G", "T"}
- dateFormat = "02.Jan'06" // uses the "reference time" https://golang.org/pkg/time/#Time.Format
- timeFormat = "15:04"
- start int64 // keep track of execution time
- stdout = colorable.NewColorableStdout() // write to this to allow ANSI color codes to be compatible on Windows
-)
-
-// func LsGo(cmd *cobra.Command, args []string) {
-func LsGo() error {
- var err error
-
- textcol.Output = stdout
-
- start = time.Now().UnixNano()
- // auto-generate help text for the command with -h
- kingpin.CommandLine.HelpFlag.Short('h')
-
- // parse the arguments and populate the struct
- kingpin.Parse()
- argsPostParse()
-
- // separate the directories from the regular files
- dirs := []string{}
- files := []os.FileInfo{}
- for _, pathStr := range *args.paths {
- var fileStat os.FileInfo
- fileStat, err = os.Stat(pathStr)
- if err != nil && strings.Contains(err.Error(), "no such file or directory") {
- printErrorHeader(err, prettifyPath(pathStr))
- continue
- } else {
- check(err)
- }
- if fileStat.IsDir() {
- dirs = append(dirs, pathStr)
- } else {
- files = append(files, fileStat)
- }
- }
-
- // list files first
- if len(files) > 0 {
- pwd := os.Getenv("PWD")
- listFiles(pwd, &files, true)
- }
-
- // then list the contents of each directory
- for i, dir := range dirs {
- // print a blank line between directories, but not before the first one
- if i > 0 {
- fmt.Fprintln(stdout, "")
- }
- listDir(dir)
- }
-
- return err
-}
-
-func listDir(pathStr string) {
- items, err := ioutil.ReadDir(pathStr)
- // if we couldn't read the folder, print a "header" with error message and use error-looking colors
- if err != nil {
- if strings.Contains(err.Error(), "no such file or directory") || strings.Contains(err.Error(), "permission denied") {
- printErrorHeader(err, prettifyPath(pathStr))
- return
- }
- check(err)
- }
-
- // filter by the regexp if one was passed
- if len(*args.find) > 0 {
- filteredItems := []os.FileInfo{}
- for _, fileInfo := range items {
- re, err := regexp.Compile(*args.find)
- check(err)
- if re.MatchString(fileInfo.Name()) {
- filteredItems = append(filteredItems, fileInfo)
- }
- }
- items = filteredItems
- }
-
- if !(len(*args.find) > 0 && len(items) == 0) &&
- !(len(*args.paths) == 1 && (*args.paths)[0] == "." && !*args.recurse) {
- printFolderHeader(pathStr)
- }
-
- if len(items) > 0 {
- listFiles(pathStr, &items, false)
- }
-
- if *args.recurse {
- for _, item := range items {
- if item.IsDir() && (item.Name()[0] != '.' || *args.all) {
- fmt.Fprintln(stdout, "") // put a blank line between directories
- listDir(path.Join(pathStr, item.Name()))
- }
- }
- }
-}
-
-func listFiles(parentDir string, items *[]os.FileInfo, forceDotfiles bool) {
- absPath, err := filepath.Abs(parentDir)
- check(err)
-
- // collect all the contents here
- files := []*DisplayItem{}
- dirs := []*DisplayItem{}
-
- // to help with formatting, we need to know the length of the longest name to add appropriate padding
- longestOwnerName := 0
- longestGroupName := 0
- if *args.owner {
- for _, fileInfo := range *items {
- owner, group := getOwnerAndGroup(&fileInfo)
- longestOwnerName = max(longestOwnerName, len(owner))
- longestGroupName = max(longestGroupName, len(group))
- }
- }
-
- for _, fileInfo := range *items {
- // if this is a dotfile (hidden file)
- if fileInfo.Name()[0] == '.' {
- // we can skip everything with this file if we aren't using the `all` option
- if !*args.all && !forceDotfiles {
- continue
- }
- }
-
- basename, ext := splitExt(fileInfo.Name())
-
- displayItem := DisplayItem{
- info: fileInfo,
- ext: ext,
- basename: basename,
- }
-
- // read some info about linked file if this item is a symlink
- if fileInfo.Mode()&os.ModeSymlink != 0 {
- getLinkInfo(&displayItem, absPath)
- }
-
- if fileInfo.IsDir() || (fileInfo.Mode()&os.ModeSymlink != 0 &&
- displayItem.link.info != nil &&
- displayItem.link.info.IsDir()) {
- if *args.files {
- continue
- } else {
- dirs = append(dirs, &displayItem)
- }
- } else {
- if *args.dirs {
- continue
- } else {
- files = append(files, &displayItem)
- }
- }
-
- owner, group := getOwnerAndGroup(&fileInfo)
- ownerColor, groupColor := getOwnerAndGroupColors(owner, group)
-
- if *args.perms {
- displayItem.display += permString(fileInfo, ownerColor, groupColor)
- }
-
- if *args.owner {
- paddedOwner := pad.Right(owner, longestOwnerName, " ")
- ownerInfo := []string{Reset + ownerColor + paddedOwner}
- if !*args.nogroup {
- paddedGroup := pad.Right(group, longestGroupName, " ")
- ownerInfo = append(ownerInfo, groupColor+paddedGroup)
- }
- ownerInfo = append(ownerInfo, Reset)
- displayItem.display += strings.Join(ownerInfo, " ")
- }
-
- if *args.bytes {
- if fileInfo.Mode()&os.ModeDevice != 0 {
- displayItem.display += deviceNumbers(path.Join(absPath, fileInfo.Name()))
- } else {
- displayItem.display += sizeString(fileInfo.Size())
- }
- }
-
- if *args.mdate {
- displayItem.display += timeString(fileInfo.ModTime())
- }
-
- displayItem.display += nameString(&displayItem)
-
- if *args.links && fileInfo.Mode()&os.ModeSymlink != 0 {
- displayItem.display += linkString(&displayItem, absPath)
- }
- }
-
- if *args.sortTime {
- sort.Sort(ByTime(dirs))
- sort.Sort(ByTime(files))
- if *args.backwards {
- reverse(dirs)
- reverse(files)
- }
- }
-
- if *args.sortSize {
- sort.Sort(BySize(files))
- if *args.backwards {
- reverse(files)
- }
- }
-
- if *args.sortKind {
- sort.Sort(ByKind(files))
- if *args.backwards {
- reverse(files)
- }
- }
-
- // combine the items together again after sorting
- allItems := append(dirs, files...)
-
- // if using "long" display, just print one item per line
- if *args.bytes || *args.mdate || *args.owner || *args.perms || *args.long {
- for _, item := range allItems {
- fmt.Fprintln(stdout, item.display)
- }
- } else {
- // but if not, try to format in columns, link `ls` would
- strs := []string{}
- for _, item := range allItems {
- strs = append(strs, item.display)
- }
- textcol.PrintColumns(&strs, 2)
- }
-
- if *args.stats {
- printStats(len(files), len(dirs))
- }
-}
-
-func getLinkInfo(item *DisplayItem, absPath string) {
- fullPath := path.Join(absPath, item.info.Name())
- linkPath, err1 := os.Readlink(fullPath)
- check(err1)
-
- linkFullPath := linkPath
- if linkPath[0] != '/' {
- linkFullPath = path.Join(absPath, linkPath)
- }
-
- linkInfo, err2 := os.Stat(linkFullPath)
- if *args.linkRel {
- linkRel, _ := filepath.Rel(absPath, linkPath)
- if linkRel != "" && len(linkRel) <= len(linkPath) {
- // i prefer the look of these relative paths prepended with ./
- if linkRel[0] != '.' {
- linkPath = "./" + linkRel
- } else {
- linkPath = linkRel
- }
- }
- }
-
- link := LinkInfo{
- path: linkPath,
- }
- item.link = &link
- if linkInfo != nil {
- link.info = linkInfo
- } else if strings.Contains(err2.Error(), "no such file or directory") {
- link.broken = true
- } else if !strings.Contains(err2.Error(), "permission denied") {
- check(err2)
- }
-}
-
-func nameString(item *DisplayItem) string {
- mode := item.info.Mode()
- name := item.info.Name()
- if mode&os.ModeDir != 0 {
- return dirString(item)
- } else if mode&os.ModeSymlink != 0 {
- if !item.link.broken && item.link.info.IsDir() {
- color := ConfigColor["link"]["nameDir"]
- if *args.nerdfont {
- var linkIcon string
- if item.link.broken {
- linkIcon = otherIcons["brokenLink"]
- } else {
- linkIcon = otherIcons["linkDir"]
- }
- return color + linkIcon + " " + name + " " + Reset
- } else if *args.icons {
- return color + "🔗 " + name + " " + Reset
- } else {
- return color + " " + name + " " + Reset
- }
- } else {
- color := ConfigColor["link"]["name"]
- if *args.nerdfont {
- var linkIcon string
- if item.link.broken {
- linkIcon = otherIcons["brokenLink"]
- } else {
- linkIcon = otherIcons["link"]
- }
- return color + linkIcon + " " + name + " " + Reset
- } else if *args.icons {
- return color + "🔗 " + name + " " + Reset
- } else {
- return color + name + " " + Reset
- }
- }
- } else if mode&os.ModeDevice != 0 {
- color := ConfigColor["device"]["name"]
- if *args.nerdfont {
- return color + otherIcons["device"] + " " + name + " " + Reset
- } else if *args.icons {
- return color + "💽 " + name + " " + Reset
- } else {
- return color + " " + name + " " + Reset
- }
- } else if mode&os.ModeNamedPipe != 0 {
- return ConfigColor["pipe"]["name"] + " " + name + " " + Reset
- } else if mode&os.ModeSocket != 0 {
- return ConfigColor["socket"]["name"] + " " + name + " " + Reset
- }
- return fileString(item)
-}
-
-func linkString(item *DisplayItem, absPath string) string {
- colors := ConfigColor["link"]
- displayStrings := []string{colors["arrow"] + "►"}
- if item.link.info == nil && item.link.broken {
- displayStrings = append(displayStrings, colors["broken"]+item.link.path+Reset)
- } else if item.link.info != nil {
- linkname, linkext := splitExt(item.link.path)
- displayItem := DisplayItem{
- info: item.link.info,
- basename: linkname,
- ext: linkext,
- }
- displayStrings = append(displayStrings, nameString(&displayItem))
- } else {
- displayStrings = append(displayStrings, item.link.path)
- }
- return strings.Join(displayStrings, " ")
-}
-
-func fileString(item *DisplayItem) string {
- key := strings.ToLower(item.ext)
- // figure out which color to choose
- colors := FileColor["_default"]
- alias, hasAlias := FileAliases[key]
- if hasAlias {
- key = alias
- }
- betterColor, hasBetterColor := FileColor[key]
- if hasBetterColor {
- colors = betterColor
- }
-
- ext := item.ext
- if ext != "" {
- ext = "." + ext
- }
-
- // in some cases files have icons if front
- // if nerd font enabled, then it'll be a file-specific icon, or if its an executable script, a little shell icon
- // if the regular --icons flag is used instead, then it will show a ">_" only if the file is executable
- icon := ""
- executable := isExecutableScript(item)
- if *args.nerdfont {
- if executable {
- icon = colors[0] + getIconForFile("", "shell") + " "
- } else {
- icon = colors[0] + getIconForFile(item.basename, item.ext) + " "
- }
- } else if *args.icons {
- if executable {
- icon = BgGray(1) + FgRGB(0, 5, 0) + ">_" + Reset + " "
- }
- }
- displayStrings := []string{icon, colors[0], item.basename, colors[1], ext, Reset}
- return strings.Join(displayStrings, "")
-}
-
-// check for executable permissions
-func isExecutableScript(item *DisplayItem) bool {
- if item.info.Mode()&0111 != 0 && item.info.Mode().IsRegular() {
- return true
- }
- return false
-}
-
-func dirString(item *DisplayItem) string {
- colors := ConfigColor["dir"]
- if item.basename == "" {
- colors = ConfigColor[".dir"]
- }
- displayStrings := []string{colors["name"]}
- icon := ""
- if *args.icons {
- displayStrings = append(displayStrings, "📂 ")
- } else if *args.nerdfont {
- icon = getIconForFolder(item.info.Name()) + " "
- displayStrings = append(displayStrings, icon)
- } else {
- displayStrings = append(displayStrings, " ")
- }
- ext := item.ext
- if ext != "" {
- ext = "." + ext
- }
- displayStrings = append(displayStrings, item.basename, colors["ext"], ext, " ", Reset)
- return strings.Join(displayStrings, "")
-}
-
-func rwxString(mode os.FileMode, i uint, color string) string {
- bits := mode >> (i * 3)
- coloredStrings := []string{color}
- if bits&4 != 0 {
- coloredStrings = append(coloredStrings, "r")
- } else {
- coloredStrings = append(coloredStrings, "-")
- }
- if bits&2 != 0 {
- coloredStrings = append(coloredStrings, "w")
- } else {
- coloredStrings = append(coloredStrings, "-")
- }
- if i == 0 && mode&os.ModeSticky != 0 {
- if bits&1 != 0 {
- coloredStrings = append(coloredStrings, "t")
- } else {
- coloredStrings = append(coloredStrings, "T")
- }
- } else {
- if bits&1 != 0 {
- coloredStrings = append(coloredStrings, "x")
- } else {
- coloredStrings = append(coloredStrings, "-")
- }
- }
- return strings.Join(coloredStrings, "")
-}
-
-// generates the permissions string, ya know like "drwxr-xr-x" and stuff like that
-func permString(info os.FileInfo, ownerColor string, groupColor string) string {
- defaultColor := PermsColor["other"]["_default"]
-
- // info.Mode().String() does not produce the same output as `ls`, so we must build that string manually
- mode := info.Mode()
- // this "type" is not the file extension, but type as far as the OS is concerned
- filetype := "-"
- if mode&os.ModeDir != 0 {
- filetype = "d"
- } else if mode&os.ModeSymlink != 0 {
- filetype = "l"
- } else if mode&os.ModeDevice != 0 {
- if mode&os.ModeCharDevice == 0 {
- filetype = "b" // block device
- } else {
- filetype = "c" // character device
- }
- } else if mode&os.ModeNamedPipe != 0 {
- filetype = "p"
- } else if mode&os.ModeSocket != 0 {
- filetype = "s"
- }
- coloredStrings := []string{defaultColor, filetype}
- coloredStrings = append(coloredStrings, rwxString(mode, 2, ownerColor))
- coloredStrings = append(coloredStrings, rwxString(mode, 1, groupColor))
- coloredStrings = append(coloredStrings, rwxString(mode, 0, defaultColor), Reset, Reset)
- return strings.Join(coloredStrings, " ")
-}
-
-func sizeString(size int64) string {
- sizeFloat := float64(size)
- for i, unit := range sizeUnits {
- base := math.Pow(1024, float64(i))
- if sizeFloat < base*1024 {
- var sizeStr string
- if i == 0 {
- sizeStr = strconv.FormatInt(size, 10)
- } else {
- sizeStr = fmt.Sprintf("%.2f", sizeFloat/base)
- }
- return SizeColor[unit] + pad.Left(sizeStr, 6, " ") + unit + " " + Reset
- }
- }
- return strconv.Itoa(int(size))
-}
-
-func timeString(modtime time.Time) string {
- dateStr := modtime.Format(dateFormat)
- timeStr := modtime.Format(timeFormat)
- hour, err := strconv.Atoi(timeStr[0:2])
- check(err)
- // generate a color based on the hour of the day. darkest around midnight and whitest around noon
- timeColor := 14 - int(8*math.Cos(math.Pi*float64(hour)/12))
- colored := []string{FgGray(22) + dateStr, FgGray(timeColor) + timeStr, Reset}
- return strings.Join(colored, " ")
-}
-
-// when we list out any subdirectories, print those paths conspicuously above the contents
-// this helps with visual separation
-func printFolderHeader(pathStr string) {
- colors := ConfigColor["folderHeader"]
- headerString := colors["arrow"] + "►" + colors["main"] + " "
- prettyPath := prettifyPath(pathStr)
-
- if prettyPath == "/" {
- headerString += "/"
- } else {
- folders := strings.Split(prettyPath, "/")
- coloredFolders := make([]string, 0, len(folders))
- for i, folder := range folders {
- if i == len(folders)-1 { // different color for the last folder in the path
- coloredFolders = append(coloredFolders, colors["lastFolder"]+folder)
- } else {
- coloredFolders = append(coloredFolders, colors["main"]+folder)
- }
- }
- headerString += strings.Join(coloredFolders, colors["slash"]+"/")
- }
-
- fmt.Fprintln(stdout, headerString+" "+Reset)
-}
-
-func printErrorHeader(err error, pathStr string) {
- fmt.Fprintln(stdout, ConfigColor["folderHeader"]["error"]+"► "+pathStr+Reset)
- fmt.Fprintln(stdout, err.Error())
-}
-
-func prettifyPath(pathStr string) string {
- prettyPath, err := filepath.Abs(pathStr)
- check(err)
- pwd := os.Getenv("PWD")
- home := os.Getenv("HOME")
-
- if strings.HasPrefix(prettyPath, pwd) {
- prettyPath = "." + prettyPath[len(pwd):]
- } else if strings.HasPrefix(prettyPath, home) {
- prettyPath = "~" + prettyPath[len(home):]
- }
- return prettyPath
-}
-
-func getOwnerAndGroupColors(owner string, group string) (string, string) {
- if owner == os.Getenv("USER") {
- owner = "_self"
- }
- ownerColor := PermsColor["user"][owner]
- if ownerColor == "" {
- ownerColor = PermsColor["user"]["_default"]
- }
- groupColor := PermsColor["group"][group]
- if groupColor == "" {
- groupColor = PermsColor["group"]["_default"]
- }
- return ownerColor, groupColor
-}
-
-func printStats(numFiles, numDirs int) {
- colors := ConfigColor["stats"]
- end := time.Now().UnixNano()
- microSeconds := (end - start) / int64(time.Microsecond)
- milliSeconds := float64(microSeconds) / 1000
- statStrings := []string{
- colors["text"],
- colors["number"] + strconv.Itoa(numDirs),
- colors["text"] + "dirs",
- colors["number"] + strconv.Itoa(numFiles),
- colors["text"] + "files",
- colors["ms"] + fmt.Sprintf("%.2f", milliSeconds),
- colors["text"] + "ms",
- Reset,
- }
- fmt.Fprintln(stdout, strings.Join(statStrings, " "))
-}
-
-func splitExt(filename string) (basepath, ext string) {
- basename := filepath.Base(filename)
- if basename[0] == '.' {
- ext = basename[1:]
- basepath = filename[:len(filename)-len(ext)-1]
- } else {
- ext = filepath.Ext(filename)
- basepath = filename[:len(filename)-len(ext)]
- if ext != "" {
- ext = ext[1:]
- }
- }
- return
-}
-
-// Go doesn't provide a `Max` function for ints like it does for floats (wtf?)
-func max(a int, b int) int {
- if a > b {
- return a
- }
- return b
-}
-
-func check(err error) {
- if err != nil {
- panic(err)
- }
-}
diff --git a/lsgo/sort.go b/lsgo/sort.go
deleted file mode 100644
index 22a25f5e9..000000000
--- a/lsgo/sort.go
+++ /dev/null
@@ -1,67 +0,0 @@
-package lsgo
-
-// BySize tells `sort.Sort` how to sort by file size
-type BySize []*DisplayItem
-
-func (s BySize) Less(i, j int) bool {
- return s[i].info.Size() < s[j].info.Size()
-}
-func (s BySize) Len() int {
- return len(s)
-}
-func (s BySize) Swap(i, j int) {
- s[i], s[j] = s[j], s[i]
-}
-
-// ByTime tells `sort.Sort` how to sort by last modified time
-type ByTime []*DisplayItem
-
-func (s ByTime) Less(i, j int) bool {
- return s[i].info.ModTime().Unix() < s[j].info.ModTime().Unix()
-}
-func (s ByTime) Len() int {
- return len(s)
-}
-func (s ByTime) Swap(i, j int) {
- s[i], s[j] = s[j], s[i]
-}
-
-// ByKind tells `sort.Sort` how to sort by file extension
-type ByKind []*DisplayItem
-
-func (s ByKind) Less(i, j int) bool {
- var kindi, kindj string
- if s[i].basename == "" {
- kindi = "."
- } else if s[i].ext == "" {
- kindi = "0"
- } else {
- kindi = s[i].ext
- }
- if s[j].basename == "" {
- kindj = "."
- } else if s[j].ext == "" {
- kindj = "0"
- } else {
- kindj = s[j].ext
- }
- if kindi == kindj {
- if kindi == "." {
- return s[i].ext < s[j].ext
- }
- return s[i].basename < s[j].basename
- }
- return kindi < kindj
-}
-func (s ByKind) Len() int {
- return len(s)
-}
-func (s ByKind) Swap(i, j int) {
- s[i], s[j] = s[j], s[i]
-}
-
-func reverse(s []*DisplayItem) {
- for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
- s[i], s[j] = s[j], s[i]
- }
-}
diff --git a/mmGit/gitFilesystem.go b/mmGit/gitFilesystem.go
deleted file mode 100644
index 2622c127b..000000000
--- a/mmGit/gitFilesystem.go
+++ /dev/null
@@ -1,692 +0,0 @@
-package mmGit
-
-import (
- "GoSungrow/Only"
- "bufio"
- "context"
- "errors"
- "fmt"
- "github.com/go-git/go-git/v5"
- "github.com/go-git/go-git/v5/plumbing"
- "github.com/go-git/go-git/v5/plumbing/object"
- "github.com/go-git/go-git/v5/plumbing/transport/ssh"
- "os"
- "os/exec"
- "os/signal"
- "os/user"
- "path/filepath"
- "strings"
- "syscall"
- "time"
-)
-
-
-func (z *Git) Connect() error {
-
- for range Only.Once {
- if z.IsNotOk() {
- break
- }
-
- var ok bool
- ok, z.Error = IsDirExists(z.RepoDir)
- if z.Error != nil {
- break
- }
- if ok {
- z.Error = z.Open()
- break
- }
-
- z.Error = z.Clone()
- if z.Error != nil {
- break
- }
- }
-
- return z.Error
-}
-
-func (z *Git) Open() error {
-
- for range Only.Once {
- if z.IsNotOk() {
- break
- }
-
- z.repo, z.Error = git.PlainOpen(z.RepoDir)
- if z.Error != nil {
- break
- }
-
- z.worktree, z.Error = z.repo.Worktree()
- if z.Error != nil {
- break
- }
-
- var ref *plumbing.Reference
- ref, z.Error = z.repo.Head()
- if z.Error != nil {
- break
- }
-
- if ref.Hash().IsZero() {
- z.Error = errors.New("invalid HEAD reference")
- break
- }
-
- fmt.Printf("Git opened\n\trepo: %s\n\tdir: %s\n", z.RepoUrl, z.RepoDir)
- }
-
- return z.Error
-}
-
-func (z *Git) Clone() error {
-
- for range Only.Once {
- if z.IsNotOk() {
- break
- }
-
- var ok bool
- ok, z.Error = IsDirExists(z.RepoDir)
- if z.Error != nil {
- break
- }
- if ok {
- z.Error = errors.New(fmt.Sprintf("Cannot clone - directory '%s' already exists.", z.RepoDir))
- break
- }
-
- // CONTEXT: Provide Ctrl-C capability as well as operation timeouts.
- stop := make(chan os.Signal, 1)
- signal.Notify(stop, os.Interrupt)
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
- go func() {
- <-stop
- fmt.Println("\nCanceling operation...")
- cancel()
- }()
- // CONTEXT: Provide Ctrl-C capability as well as operation timeouts.
-
- pk := z.GetSshAuth()
- if z.Error != nil {
- break
- }
-
- options := &git.CloneOptions {
- URL: z.RepoUrl,
- Auth: pk,
- RemoteName: "",
- ReferenceName: "",
- SingleBranch: false,
- NoCheckout: false,
- Depth: 0,
- RecurseSubmodules: 0,
- Progress: os.Stdout,
- Tags: 0,
- InsecureSkipTLS: false,
- CABundle: nil,
- }
- z.repo, z.Error = git.PlainCloneContext(ctx, z.RepoDir, false, options)
- if z.Error != nil {
- break
- }
- z.worktree, z.Error = z.repo.Worktree()
- if z.Error != nil {
- break
- }
-
- var ref *plumbing.Reference
- ref, z.Error = z.repo.Head()
- if z.Error != nil {
- break
- }
-
- if ref.Hash().IsZero() {
- z.Error = errors.New("invalid HEAD reference")
- break
- }
-
- fmt.Printf("Git cloned\n\trepo: %s\n\tdir: %s\n", z.RepoUrl, z.RepoDir)
- }
-
- return z.Error
-}
-
-// GetSshAuth: Gitlab keys need to be created with at least 3072 bits.
-// ssh-keygen -t rsa -b 3072 -C 'root@everywhere' -f gitlab_rsa -N ''
-func (z *Git) GetSshAuth() *ssh.PublicKeys {
- var pk *ssh.PublicKeys
-
- for range Only.Once {
- if z.IsNotOk() {
- break
- }
-
- var u *user.User
- u, z.Error = user.Current()
-
- paths := []string {
- z.KeyFile,
- filepath.Join(u.HomeDir, ".ssh", "id_rsa"),
- }
-
- var path string
- for _, path = range paths {
- if path == "" {
- continue
- }
-
- z.Error = checkKeyFile(path)
- if z.Error != nil {
- continue
- }
-
- break
- }
-
- // Try without password first.
- var password string
- pk, z.Error = ssh.NewPublicKeysFromFile("git", path, password)
- if z.Error == nil {
- fmt.Printf("AUTH: %v\n", pk)
- break
- }
-
- // Then with password.
- password = getPassword("ApiPassword: ")
- pk, z.Error = ssh.NewPublicKeysFromFile("git", path, password)
- if z.Error == nil {
- fmt.Printf("AUTH: %v\n", pk)
- break
- }
- }
-
- return pk
-}
-
-func checkKeyFile(path string) error {
- var err error
-
- for range Only.Once {
- if path == "" {
- continue
- }
-
- var fi os.FileInfo
- fi, err = os.Stat(path)
- if os.IsNotExist(err) {
- continue
- }
-
- if fi.IsDir() {
- err = errors.New("SSH publickey file is a directory")
- continue
- }
- }
-
- return err
-}
-
-// techEcho() - turns terminal echo on or off.
-func termEcho(on bool) {
- // Common settings and variables for both stty calls.
- attrs := syscall.ProcAttr{
- Dir: "",
- Env: []string{},
- Files: []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()},
- Sys: nil}
- var ws syscall.WaitStatus
- cmd := "echo"
- if on == false {
- cmd = "-echo"
- }
-
- // Enable/disable echoing.
- pid, err := syscall.ForkExec(
- "/bin/stty",
- []string{"stty", cmd},
- &attrs)
- if err != nil {
- panic(err)
- }
-
- // Wait for the stty process to complete.
- _, err = syscall.Wait4(pid, &ws, 0, nil)
- if err != nil {
- panic(err)
- }
-}
-
-// getPassword - Prompt for password.
-func getPassword(prompt string) string {
- fmt.Print(prompt)
-
- // Catch a ^C interrupt.
- // Make sure that we reset term echo before exiting.
- signalChannel := make(chan os.Signal, 1)
- signal.Notify(signalChannel, os.Interrupt)
- go func() {
- for _ = range signalChannel {
- fmt.Println("\n^C interrupt.")
- termEcho(true)
- os.Exit(1)
- }
- }()
-
- // Echo is disabled, now grab the data.
- termEcho(false) // disable terminal echo
- reader := bufio.NewReader(os.Stdin)
- text, err := reader.ReadString('\n')
- termEcho(true) // always re-enable terminal echo
- fmt.Println("")
- if err != nil {
- // The terminal has been reset, go ahead and exit.
- fmt.Println("ERROR:", err.Error())
- os.Exit(1)
- }
- return strings.TrimSpace(text)
-}
-
-//func (z *Git) setContext() error {
-//
-// for range Only.Once {
-// if z.IsNotOk() {
-// break
-// }
-//
-// stop := make(chan os.Signal, 1)
-// signal.Notify(stop, os.Interrupt)
-// ctx, cancel := context.WithCancel(context.Background())
-// defer cancel() // cancel when we are finished consuming integers
-//
-// go func() {
-// <-stop
-// Warning("\nSignal detected, canceling operation...")
-// cancel()
-// }()
-//
-// var auth ssh.AuthMethod
-// auth, z.Error = ssh.DefaultAuthBuilder("admin-mickh")
-// if z.Error != nil {
-// break
-// }
-//
-// z.repo, z.Error = git.PlainClone(z.RepoDir, false, &git.CloneOptions {
-// URL: z.RepoUrl,
-// Auth: auth,
-// })
-// if z.Error != nil {
-// break
-// }
-//
-// var ref *plumbing.Reference
-// ref, z.Error = z.repo.Head()
-// if z.Error != nil {
-// break
-// }
-//
-// var commit *object.Commit
-// commit, z.Error = z.repo.CommitObject(ref.Hash())
-// if z.Error != nil {
-// break
-// }
-//
-// fmt.Println(commit)
-// }
-//
-// return z.Error
-//}
-
-func (z *Git) SaveFile(fn string, data []byte) error {
-
- for range Only.Once {
- if z.IsNotOk() {
- break
- }
-
- //z.worktree, z.Error = z.repo.Worktree()
- //if z.Error != nil {
- // break
- //}
- //
- //var fh fs.File
- //var fi os.FileInfo
- //fi, z.Error = z.fs.Stat(fn)
- //if errors.Is(z.Error, os.ErrNotExist) {
- // // Create new file
- // fh, z.Error = z.fs.Create(fn)
- //} else {
- // // Open file
- // fh, z.Error = z.fs.OpenFile(fn, os.O_RDWR|os.O_CREATE, 0664)
- //}
-
- fh, err := os.OpenFile(filepath.Join(z.RepoDir, fn), os.O_RDWR|os.O_CREATE, 0664)
- if err != nil {
- z.Error = err
- break
- }
- defer fh.Close()
-
- fmt.Printf("Saved file '%s'\n", fn)
- _, z.Error = fh.Write(data)
- if z.Error != nil {
- break
- }
-
- // Run git status before adding the file to the worktree
- //fmt.Println(z.worktree.Status())
-
- // git add $filePath
- _, z.Error = z.worktree.Add(fn)
- if z.Error != nil {
- break
- }
-
- //// Run git status after the file has been added adding to the worktree
- //fmt.Println(z.worktree.Status())
- //
- //// git commit -m $message
- //msg := fmt.Sprintf("Updated file '%s'", fn)
- //_, z.Error = z.worktree.Commit(msg, &git.CommitOptions{})
- //if z.Error != nil {
- // break
- //}
-
- }
-
- return z.Error
-}
-
-func (z *Git) Status() error {
-
- for range Only.Once {
- if z.IsNotOk() {
- break
- }
-
- var status git.Status
- status, z.Error = z.worktree.Status()
- if z.Error != nil {
- break
- }
-
- if status.String() != "" {
- fmt.Printf("Status of Git\n\trepo: %s\n\tdir: %s\n%s\n",
- z.RepoUrl,
- z.RepoDir,
- status.String(),
- )
- }
- }
-
- return z.Error
-}
-
-func (z *Git) Add(path string) error {
-
- for range Only.Once {
- if z.IsNotOk() {
- break
- }
-
- if path == "" {
- path = "."
- }
-
- fmt.Printf("Adding to Git\n\trepo: %s\n\tdir: %s\n", z.RepoUrl, z.RepoDir)
-
- _, z.Error = z.worktree.Add(path)
- if z.Error != nil {
- break
- }
-
- z.Error = z.Status()
- if z.Error != nil {
- break
- }
- }
-
- //PrintError(z.Error)
- return z.Error
-}
-
-func (z *Git) Commit(msg string, args ...interface{}) error {
-
- for range Only.Once {
- if z.IsNotOk() {
- break
- }
-
- z.Error = z.Add(".")
- if z.Error != nil {
- break
- }
-
- cn := &object.Signature {
- Name: os.Getenv("USERNAME"),
- Email: "",
- When: time.Now(),
- }
-
- fmt.Printf("Committing Git\n\trepo: %s\n\tdir: %s\n", z.RepoUrl, z.RepoDir)
- // Similar to git commit -m $message
- var ph plumbing.Hash
- msg := fmt.Sprintf(msg, args...)
- ph, z.Error = z.worktree.Commit(msg, &git.CommitOptions{
- All: false,
- Author: cn,
- Committer: cn,
- Parents: nil,
- SignKey: nil,
- })
- if z.Error != nil {
- break
- }
-
- // Similar to git show -s
- var obj *object.Commit
- obj, z.Error = z.repo.CommitObject(ph)
- if z.Error != nil {
- break
- }
-
- if obj.String() != "" {
- fmt.Printf("Status of Git\n\trepo: %s\n\tdir: %s\n%s\n",
- z.RepoUrl,
- z.RepoDir,
- obj.String(),
- )
- }
- }
-
- //PrintError(z.Error)
- return z.Error
-}
-
-func (z *Git) Pull() error {
-
- for range Only.Once {
- if z.IsNotOk() {
- break
- }
-
- pk := z.GetSshAuth()
- if z.Error != nil {
- break
- }
-
- fmt.Printf("Pulling Git\n\trepo: %s\n\tdir: %s\n", z.RepoUrl, z.RepoDir)
- z.Error = z.worktree.Pull(&git.PullOptions {
- RemoteName: "",
- ReferenceName: "",
- SingleBranch: false,
- Depth: 0,
- Auth: pk,
- RecurseSubmodules: 0,
- Progress: os.Stdout,
- Force: false,
- InsecureSkipTLS: false,
- CABundle: nil,
- })
- if z.Error.Error() == "already up-to-date" {
- z.Error = nil
- break
- }
- if z.Error != nil {
- break
- }
- }
-
- //PrintError(z.Error)
- return z.Error
-}
-
-func (z *Git) Push() error {
-
- for range Only.Once {
- if z.IsNotOk() {
- break
- }
-
- z.Error = z.Commit("Updated")
- if z.Error != nil {
- break
- }
-
- pk := z.GetSshAuth()
- if z.Error != nil {
- break
- }
-
- fmt.Printf("Pushing Git\n\trepo: %s\n\tdir: %s\n", z.RepoUrl, z.RepoDir)
- z.Error = z.repo.Push(&git.PushOptions{
- RemoteName: "",
- RefSpecs: nil,
- Auth: pk,
- Progress: os.Stdout,
- Prune: false,
- Force: false,
- InsecureSkipTLS: false,
- CABundle: nil,
- RequireRemoteRefs: nil,
- })
- if z.Error != nil {
- break
- }
- }
-
- //PrintError(z.Error)
- return z.Error
-}
-
-func (z *Git) Diff(path string) error {
-
- for range Only.Once {
- var c []CommitDiffs
-
- c, z.Error = z.GetDiffs(path)
- if z.Error != nil {
- break
- }
-
- if len(c) < 2 {
- fmt.Printf("Not enough revisions to compare.\n")
- break
- }
-
- f1 := fmt.Sprintf("%s-%s", path, c[0].Hash)
- f1, z.Error = WriteTempFile(f1, c[0].Contents)
- if z.Error != nil {
- break
- }
-
- f2 := fmt.Sprintf("%s-%s", path, c[1].Hash)
- f2, z.Error = WriteTempFile(f2, c[1].Contents)
- if z.Error != nil {
- break
- }
-
- if z.DiffCmd == "" {
- z.DiffCmd = "tkdiff"
- }
- z.DiffCmd, z.Error = exec.LookPath(z.DiffCmd)
-
- cmd := exec.Command(z.DiffCmd, f1, f2)
-
- var out []byte
- out, z.Error = cmd.Output()
- //if z.Error != nil {
- // break
- //}
-
- fmt.Printf("# %s\n", cmd.String())
-
- fmt.Println(string(out))
- if z.Error != nil {
- break
- }
- }
-
- //PrintError(z.Error)
- return z.Error
-}
-
-type CommitDiffs struct {
- Hash string
- Contents string
-}
-
-func (z *Git) GetDiffs(path string) ([]CommitDiffs, error) {
- var ret []CommitDiffs
-
- for range Only.Once {
- if z.IsNotOk() {
- break
- }
-
- fmt.Printf("Diff Git\n\trepo: %s\n\tdir: %s\n", z.RepoUrl, z.RepoDir)
- ref, _ := z.repo.Head()
- //fmt.Printf("ref '%s'\n", ref.String())
-
- commit, _ := z.repo.CommitObject(ref.Hash())
- //fmt.Printf("commit '%s'\n", commit.String())
-
- var comm []*object.Commit
- commitIter, _ := z.repo.Log(&git.LogOptions{From: commit.Hash})
-
- _ = commitIter.ForEach(func(c *object.Commit) error {
- comm = append(comm, c)
- return nil
- })
-
- var lastHash string
- //for k := 0; k < len(comm)-1; k++ {
- for k, _ := range comm {
- fmt.Printf("# Commit number[%d]: %s", k, comm[k].Hash)
- f2, _ := comm[k].File(path)
- if f2 == nil {
- fmt.Println(" - no path")
- continue
- }
-
- fc, _ := f2.Contents()
- hs := GetHash(fc)
- if hs == lastHash {
- fmt.Println(" - no change")
- continue
- }
- lastHash = hs
-
- ret = append(ret, CommitDiffs{
- Hash: comm[k].Hash.String(),
- Contents: fc,
- })
- fmt.Println(" - changed")
- }
- }
-
- return ret, z.Error
-}
diff --git a/mmGit/gitInMemory.go b/mmGit/gitInMemory.go
deleted file mode 100644
index 34b98eeae..000000000
--- a/mmGit/gitInMemory.go
+++ /dev/null
@@ -1,137 +0,0 @@
-package mmGit
-
-import (
- "GoSungrow/Only"
- "fmt"
- memfs "github.com/go-git/go-billy/v5/memfs"
- git "github.com/go-git/go-git/v5"
- "github.com/go-git/go-git/v5/plumbing/transport/ssh"
- memory "github.com/go-git/go-git/v5/storage/memory"
- "os"
- //"net/http"
-)
-
-func (z *Git) MemConnect() error {
-
- for range Only.Once {
- if z.IsNotOk() {
- break
- }
-
- //auth := &http.BasicAuth {
- // ApiUsername: z.ApiUsername,
- // ApiPassword: z.ApiPassword,
- //}
-
- var auth ssh.AuthMethod
- auth, z.Error = ssh.DefaultAuthBuilder("admin-mickh")
- if z.Error != nil {
- break
- }
-
- //if z.Error = r.Push(&git.PushOptions{Auth: sshAuth}); err != nil {
- // log.Error().Err(err).Msg("Push err")
- // os.Exit(1)
- //}
- //if z.Error = r.Push(&git.PushOptions{Auth: sshAuth}); err != nil {
- // log.Error().Err(err).Msg("Push err")
- // os.Exit(1)
- //}
-
- //s := fmt.Sprintf("%s/.ssh/id_rsa", os.Getenv("HOME"))
- //sshKey, err = ioutil.FileRead(s)
- //signer, err := ssh.ParsePrivateKey([]byte(sshKey))
- //auth = &gitssh.PublicKeys{User: "git", Signer: signer}
-
- z.storer = memory.NewStorage()
- z.fs = memfs.New()
-
- z.repo, z.Error = git.Clone(z.storer, z.fs, &git.CloneOptions{
- URL: z.RepoUrl,
- Auth: auth,
- })
- if z.Error != nil {
- break
- }
- }
-
- return z.Error
-}
-
-func (z *Git) MemSaveFile(fn string, data []byte) error {
-
- for range Only.Once {
- if z.IsNotOk() {
- break
- }
-
- z.worktree, z.Error = z.repo.Worktree()
- if z.Error != nil {
- break
- }
-
- //var fh fs.File
- //var fi os.FileInfo
- //fi, z.Error = z.fs.Stat(fn)
- //if errors.Is(z.Error, os.ErrNotExist) {
- // // Create new file
- // fh, z.Error = z.fs.Create(fn)
- //} else {
- // // Open file
- // fh, z.Error = z.fs.OpenFile(fn, os.O_RDWR|os.O_CREATE, 0664)
- //}
-
- fh, err := z.fs.OpenFile(fn, os.O_RDWR|os.O_CREATE, 0664)
- if err != nil {
- z.Error = err
- break
- }
- defer fh.Close()
-
- _, z.Error = fh.Write(data)
- if z.Error != nil {
- break
- }
-
- // Run git status before adding the file to the worktree
- fmt.Println(z.worktree.Status())
-
- // git add $filePath
- _, z.Error = z.worktree.Add(fn)
- if z.Error != nil {
- break
- }
-
- // Run git status after the file has been added adding to the worktree
- fmt.Println(z.worktree.Status())
-
- // git commit -m $message
- msg := fmt.Sprintf("Updated file '%s'", fn)
- _, z.Error = z.worktree.Commit(msg, &git.CommitOptions{})
- if z.Error != nil {
- break
- }
-
- }
-
- return z.Error
-}
-
-func (z *Git) MemCommit(msg string, args ...interface{}) error {
-
- for range Only.Once {
- if z.IsNotOk() {
- break
- }
-
- // Similar to git commit -m $message
- msg := fmt.Sprintf(msg, args...)
- _, z.Error = z.worktree.Commit(msg, &git.CommitOptions{})
- if z.Error != nil {
- break
- }
-
- }
-
- return z.Error
-}
diff --git a/mmGit/struct.go b/mmGit/struct.go
deleted file mode 100644
index b094e5762..000000000
--- a/mmGit/struct.go
+++ /dev/null
@@ -1,159 +0,0 @@
-package mmGit
-
-import (
- "GoSungrow/Only"
- "errors"
- "github.com/go-git/go-billy/v5"
- "github.com/go-git/go-git/v5"
- "github.com/go-git/go-git/v5/storage/memory"
-)
-
-
-type Git struct {
- Username string
- Password string
- KeyFile string
- Token string
- RepoUrl string
- RepoDir string
- DiffCmd string
-
- repo *git.Repository
-
- modeMemory bool
- worktree *git.Worktree
- storer *memory.Storage
- fs billy.Filesystem
-
- Error error
-}
-
-func New() *Git {
- var ret Git
-
- for range Only.Once {
- }
-
- return &ret
-}
-
-func (z *Git) SetAuth(username string, password string) error {
-
- for range Only.Once {
- if username == "" {
- z.Error = errors.New("username empty")
- break
- }
- z.Username = username
-
- if password == "" {
- z.Error = errors.New("password empty")
- break
- }
- z.Password = password
- }
-
- return z.Error
-}
-
-func (z *Git) SetKeyFile(path string) error {
-
- for range Only.Once {
- if path == "" {
- break
- }
-
- z.Error = checkKeyFile(path)
- if z.Error != nil {
- break
- }
-
- z.KeyFile = path
- }
-
- return z.Error
-}
-
-func (z *Git) SetToken(t string) error {
-
- for range Only.Once {
- if t == "" {
- break
- }
-
- z.Token = t
- }
-
- return z.Error
-}
-
-func (z *Git) SetRepo(repo string) error {
-
- for range Only.Once {
- if repo == "" {
- z.Error = errors.New("repo empty")
- break
- }
- z.RepoUrl = repo
- }
-
- return z.Error
-}
-
-func (z *Git) SetDir(dir string) error {
-
- for range Only.Once {
- if dir == "" {
- z.Error = errors.New("dir empty")
- break
- }
- z.RepoDir = dir
- }
-
- return z.Error
-}
-
-func (z *Git) SetDiffCmd(cmd string) error {
-
- for range Only.Once {
- if cmd == "" {
- cmd = "tkdiff"
- }
- z.DiffCmd = cmd
- }
-
- return z.Error
-}
-
-func (z *Git) IsOk() bool {
- var ok bool
-
- for range Only.Once {
- //if z.ApiUsername == "" {
- // z.Error = errors.New("username empty")
- // break
- //}
- //
- //if z.ApiPassword == "" {
- // z.Error = errors.New("password empty")
- // break
- //}
-
- if z.RepoUrl == "" {
- z.Error = errors.New("repo empty")
- break
- }
-
- if z.RepoDir == "" {
- z.Error = errors.New("repo dir empty")
- break
- }
-
- ok = true
- }
-
- return ok
-}
-func (z *Git) IsNotOk() bool {
- return !z.IsOk()
-}
diff --git a/mmGit/utils.go b/mmGit/utils.go
deleted file mode 100644
index fd750d0e9..000000000
--- a/mmGit/utils.go
+++ /dev/null
@@ -1,87 +0,0 @@
-package mmGit
-
-import (
- "GoSungrow/Only"
- "crypto/md5"
- "encoding/hex"
- "errors"
- "fmt"
- "os"
-)
-
-
-func IsDirExists(path string) (bool, error) {
- var ok bool
- var err error
-
- for range Only.Once {
- if path == "" {
- err = errors.New("empty git dir path")
- break
- }
-
- var fi os.FileInfo
- fi, err = os.Stat(path)
- if os.IsNotExist(err) {
- err = nil
- break
- }
-
- if !fi.IsDir() {
- err = errors.New("git path is not a dir")
- break
- }
-
- ok = true
- }
-
- return ok, err
-}
-
-func PrintError(err error) {
- if err == nil {
- fmt.Println("OK")
- return
- }
- fmt.Printf("\nERROR: %s\n", err)
-}
-
-func GetHash(data string) string {
- var ret string
-
- for range Only.Once {
- h := md5.New()
- h.Write([]byte(data))
- ret = hex.EncodeToString(h.Sum(nil))
- }
-
- return ret
-}
-
-func WriteTempFile(path string, data string) (string, error) {
- var fn string
- var err error
-
- for range Only.Once {
- fn = fmt.Sprintf("%s/%s", os.TempDir(), path)
- fmt.Printf("Writing file %s ...", fn)
- var fh *os.File
- fh, err = os.OpenFile(fn, os.O_RDWR|os.O_CREATE, 0664)
- if err != nil {
- fmt.Printf("%s\n", err)
- break
- }
- defer fh.Close()
-
- _, err = fh.Write([]byte(data))
- if err != nil {
- fmt.Printf("%s\n", err)
- break
- }
- fmt.Println("OK")
-
- //fmt.Printf("%v\n", data)
- }
-
- return fn, err
-}