From 830236663a7f4a57ff18833384c8732bbf1df314 Mon Sep 17 00:00:00 2001 From: Till Kuhn Date: Fri, 27 Sep 2024 19:51:28 +0200 Subject: [PATCH] 1st refactoring --- .golangci.yml | 57 +++++++++++++++++ CONTRIBUTING.md | 97 +++++++++++++++++++++++++++++ Makefile | 20 ++++-- README.adoc | 35 ++++++++--- go.mod | 17 ++++++ go.sum | 29 +++++++++ main.go | 151 +++++++++++++++++++++++++++++++++++++--------- main_test.go | 18 +++++- sqlite.png | Bin 0 -> 29611 bytes sqlite/.gitignore | 1 + sqlite/.gitkeep | 0 11 files changed, 381 insertions(+), 44 deletions(-) create mode 100644 .golangci.yml create mode 100644 CONTRIBUTING.md create mode 100644 go.sum create mode 100644 sqlite.png create mode 100644 sqlite/.gitignore create mode 100644 sqlite/.gitkeep diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..220b035 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,57 @@ +run: + timeout: 10m + issues-exit-code: 1 + tests: true + +linters: + # Enable specific linter + # https://golangci-lint.run/usage/linters/ + enable: + - cyclop # Go linter that checks if package imports are in a list of acceptable packages + #- depguard # Go linter that checks if package imports are in a list of acceptable packages + - dogsled # Checks assignments with too many blank identifiers (e.g. x, , , _, := f()) + - dupl # Tool for code clone detection + - errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13. + - exhaustive # check exhaustiveness of enum switch statements + - copyloopvar # checks for pointers to enclosing loop variables + - funlen # Tool for detection of long functions + - gochecknoglobals # A global variable is a variable declared in package scope and that can be read and written to by any function within the package. + - gocritic # Provides diagnostics that check for bugs, performance and style issues. + - goconst # Inspects source code for security problems + - gocyclo # Computes and checks the cyclomatic complexity of functions + - err113 # Golang linter to check the errors handling expressions + - gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification + - goimports # In addition to fixing imports, goimports also formats your code in the same style as gofmt. + - mnd # An analyzer to detect magic numbers. + - goprintffuncname # Checks that printf-like functions are named with f at the end + - gosec # Inspects source code for security problems + - misspell # Finds commonly misspelled English words in comments + - nakedret # Finds naked returns in functions greater than a specified function length + - nestif # Reports deeply nested if statements + - nilerr # Finds the code that returns nil even if it checks that the error is not nil. + - noctx # noctx finds sending http request without context.Context + - nolintlint # Reports ill-formed or insufficient nolint directives + - prealloc # Finds slice declarations that could potentially be pre-allocated + - promlinter # Check Prometheus metrics naming via promlint + - revive # Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint. + - unconvert # Remove unnecessary type conversions + - unparam # Reports unused function parameters + - whitespace # Tool for detection of leading and trailing whitespace + +linters-settings: + funlen: + lines: 100 + statements: 50 + +issues: + # Excluding configuration per-path, per-linter, per-text and per-source + exclude-rules: + - path: _test\.go + linters: + - gochecknoglobals + - gosec + - funlen + - noctx + # this is the exception for commit, data and version variable which with pass in using ldflags + - path: main.go + linters: [gochecknoglobals] \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..3ac262c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,97 @@ +# Source + +Content is based on [this gist](https://gist.github.com/PurpleBooth/b24679402957c63ec426). +Thanks, [Billie Thompson](https://gist.github.com/PurpleBooth)! + +# Contributing + +When contributing to this repository, please first discuss the change you wish to make via issue, +email, or any other method with the owners of this repository before making a change. + +Please note we have a code of conduct, please follow it in all your interactions with the project. + +## Pull Request Process + +1. Ensure any install or build dependencies are removed before the end of the layer when doing a + build. +2. Update the README.md with details of changes to the interface, this includes new environment + variables, exposed ports, useful file locations and container parameters. +3. Increase the version numbers in any examples files and the README.md to the new version that this + Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). +4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you + do not have permission to do that, you may request the second reviewer to merge it for you. + +## Code of Conduct + +### Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +### Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +### Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +### Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +### Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at [INSERT EMAIL ADDRESS]. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +### Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/Makefile b/Makefile index 3c0cb1d..8cff0d7 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,24 @@ +.PHONY: help +help: ## Shows the help + @echo 'Usage: make ... ' + @echo '' + @echo 'Available targets are:' + @echo '' + @grep -E '^[ a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \ + awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' | sort + @echo '' .PHONY: run -run: +run: ## Run tracker go run main.go .PHONY: test -test: +test: ## Test go code go test ./... .PHONY: lint -lint: - golangci-lint run \ No newline at end of file +lint: ## Lint go code + golangci-lint run + +update: ## Update all go dependencies + @go get -u all \ No newline at end of file diff --git a/README.adoc b/README.adoc index 78cc7e1..255d6e6 100644 --- a/README.adoc +++ b/README.adoc @@ -1,16 +1,35 @@ image:https://github.com/tillkuhn/billy-idle/actions/workflows/go.yml/badge.svg[ci-build] -= 💤 Billy Idle - Lightweight MacOS (In)activity Tracker +== 💤 Billy Idle - Lightweight MacOS (In)activity Tracker -Inspired by the article https://www.dssw.co.uk/blog/2015-01-21-inactivity-and-idle-time/[Inactivity and Idle Time on OS X]. Background: OS X has a timer called HIDIdleTime that tracks the last time you interacted with the computer. +Simple busy / idle time tracker inspired by the ancient article https://www.dssw.co.uk/blog/2015-01-21-inactivity-and-idle-time/[Inactivity and Idle Time on OS X]. Background: OS X has a timer called HIDIdleTime that tracks the last time you interacted with the computer. + +== Run [source,shell] ---- $ go run main.go -🐝 Starting in busy mode at Fri, 27 Sep 2024 16:56:05 CEST -💤 Switched to idle after 5s idle and 5s busy time at Fri, 27 Sep 2024 16:56:10 CEST -🐝 Switched to busy mode at Fri, 27 Sep 2024 16:56:51 CEST -💤 Switched to idle after 5s idle and 4s busy time at Fri, 27 Sep 2024 16:56:56 CEST -🐝 Stopped at Fri, 27 Sep 2024 16:57:04 CEST ----- \ No newline at end of file +2024/09/27 19:44:41 [BigMac] 🐝 Start tracking in busy mode, idle time kicks in after 3s +2024/09/27 19:44:44 [BigMac] 💤 Switched to idle mode after 3s of busy time, completing record #1 +2024/09/27 19:45:23 [BigMac] 🐝 Resuming busy mode after 39s of idle time, creating new record +2024/09/27 19:46:47 [BigMac] 💤 Switched to idle mode after 1m24s of busy time, completing record #2 +2024/09/27 19:47:44 [BigMac] 🐝 Resuming busy mode after 57s of idle time, creating new record +^C +2024/09/27 19:47:46 [BigMac] 🐝 Stopped at Fri, 27 Sep 2024 19:48:32 CEST +---- + +== Database Support + +*Billy Idle* currently only support a local https://gitlab.com/cznic/sqlite[sqlite] database, more precisely `modernc.org/sqlite` which is a cgo-free port of SQLite. But it shouldn't be a big deal to add support for a remote https://www.postgresql.org[PostgreSQL] Database. + +image:sqlite.png[] + +== 🎸 Credits + +image:https://upload.wikimedia.org/wikipedia/commons/thumb/7/74/Billy_idol_ill_artlibre_jnl.png/640px-Billy_idol_ill_artlibre_jnl.png[] +Source: https://commons.wikimedia.org/wiki/File:Billy_idol_ill_artlibre_jnl.png[Wikimedia Commons], terms of the https://en.wikipedia.org/wiki/en:Free_Art_License[Free Art License] apply. + +== Contribution + +If you want to contribute to *rubin* please have a look at the [contribution guidelines](./CONTRIBUTING.md). diff --git a/go.mod b/go.mod index 17e5404..872a3e9 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,20 @@ module github.com/tillkuhn/billy-idle go 1.23.1 + +require ( + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/ncruces/go-strftime v0.1.9 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + golang.org/x/sys v0.22.0 // indirect + modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect + modernc.org/libc v1.55.3 // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.8.0 // indirect + modernc.org/sqlite v1.33.1 // indirect + modernc.org/strutil v1.2.0 // indirect + modernc.org/token v1.1.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..db23520 --- /dev/null +++ b/go.sum @@ -0,0 +1,29 @@ +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= +modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= +modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= +modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= +modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/sqlite v1.33.1 h1:trb6Z3YYoeM9eDL1O8do81kP+0ejv+YzgyFo+Gwy0nM= +modernc.org/sqlite v1.33.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/main.go b/main.go index ae97ab7..740f85d 100644 --- a/main.go +++ b/main.go @@ -1,66 +1,157 @@ package main import ( + "context" + "database/sql" "fmt" "log" "os" "os/exec" "os/signal" + "path/filepath" "regexp" "strconv" "syscall" "time" + + _ "modernc.org/sqlite" ) const ( - dateLayout = time.RFC1123 + dateLayout = time.RFC1123 + recreateSchema = true // CAUTION !!!! ) var ( - checkInterval = 1 * time.Second - idleAfter = 5 * time.Second - idleMatcher = regexp.MustCompile("\"HIDIdleTime\"\\s*=\\s*(\\d+)") c = make(chan os.Signal, 1) cmd = "ioreg" + clientID = "default" + dbDirectory = "./sqlite" + checkInterval = 1 * time.Second + idleAfter = 3 * time.Second + idleMatcher = regexp.MustCompile("\"HIDIdleTime\"\\s*=\\s*(\\d+)") ) // main runs the tracker func main() { + ctx, ctxCancel := context.WithCancel(context.Background()) signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP) - busyStart := time.Now() - idle := false - fmt.Printf("🐝 Starting in busy mode at %v\n", time.Now().Format(dateLayout)) - go func() { - for { - cmd := exec.Command(cmd, "-c", "IOHIDSystem") - stdout, err := cmd.Output() - if err != nil { - log.Fatal(err.Error()) - } - match := idleMatcher.FindStringSubmatch(string(stdout)) - var idleMillis int64 - if match != nil { - if i, err := strconv.Atoi(match[1]); err == nil { - idleMillis = int64(i / 1000000) - } - } else { - log.Fatal("Can't parse HIDIdleTime from output" + string(stdout)) - } + db, err := initDB() + if err != nil { + log.Fatal(err) + } + defer func(db *sql.DB) { _ = db.Close() }(db) + go func() { + idle := false + lastEvent := time.Now() - if !idle && idleMillis >= idleAfter.Milliseconds() { + id, _ := insertTrack(ctx, db, fmt.Sprintf("🐝 Start tracking in busy mode, idle time kicks in after %vs", idleAfter.Seconds())) + for { + idleMillis, err := currentIdleTime(ctx) + switch { + case err != nil: + log.Println(err.Error()) + case !idle && idleMillis >= idleAfter.Milliseconds(): idle = true - fmt.Printf("💤 Switched to idle after %ds idle and %v busy time at %v\n", - idleMillis/1000, time.Since(busyStart).Round(time.Second), time.Now().Format(dateLayout)) - } else if idle && idleMillis < idleAfter.Milliseconds() { + if err := completeTrack(ctx, db, id); err != nil { + log.Println(err.Error()) + } + log.Printf("[%s] 💤 Switched to idle mode after %v of busy time, completing record #%d\n", + clientID, time.Since(lastEvent).Round(time.Second), id) + lastEvent = time.Now() + case idle && idleMillis < idleAfter.Milliseconds(): idle = false - busyStart = time.Now() - fmt.Printf("🐝 Switched to busy mode at %s\n", time.Now().Format(dateLayout)) + id, err = insertTrack(ctx, db, fmt.Sprintf("🐝 Resuming busy mode after %v of idle time, creating new record", time.Since(lastEvent).Round(time.Second))) + if err != nil { + log.Println(err.Error()) + } + lastEvent = time.Now() } time.Sleep(checkInterval) } }() <-c - fmt.Printf("🐝 Stopped at %v\n", time.Now().Format(dateLayout)) + ctxCancel() + log.Printf("🐝 Stopped at %v\n", time.Now().Format(dateLayout)) +} + +// currentIdleTime gets the current idle time in milliseconds from the external ioreg command +func currentIdleTime(ctx context.Context) (int64, error) { + cmd := exec.CommandContext(ctx, cmd, "-c", "IOHIDSystem") + stdout, err := cmd.Output() + if err != nil { + return 0, err + } + + match := idleMatcher.FindStringSubmatch(string(stdout)) + var t int64 + if match != nil { + if i, err := strconv.Atoi(match[1]); err == nil { + t = int64(i) / time.Second.Microseconds() + } + } else { + return t, fmt.Errorf("%w can't parse HIDIdleTime from output %s", err, string(stdout)) + } + return t, nil +} + +// initDB initializes SQLite DB in local filesystem +func initDB() (*sql.DB, error) { + fn := filepath.Join(dbDirectory, "db") + + db, err := sql.Open("sqlite", fn) + if err != nil { + return nil, err + } + + clientID, err = os.Hostname() + if err != nil { + return nil, err + } + + // drop table if exists t; insert into t values(42), (314); + var dropStmt string + if recreateSchema { + dropStmt = "DROP TABLE IF EXISTS track;\n" + } + if _, err = db.Exec(dropStmt + ` +CREATE TABLE IF NOT EXISTS track ( + "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, + "busy_start" DATETIME NOT NULL DEFAULT (datetime(CURRENT_TIMESTAMP, 'localtime')), + "busy_end" DATETIME, + "client" TEXT, + "message" TEXT) +`); err != nil { + return nil, err + } + + return db, nil +} + +// insertTrack inserts a new tracking records +func insertTrack(ctx context.Context, db *sql.DB, msg string) (int, error) { + log.Printf("[%s] %s", clientID, msg) + statement, err := db.PrepareContext(ctx, `INSERT INTO track(message,client) VALUES (?,?) RETURNING id;`) + if err != nil { + return 0, err + } + var id int + // Golang SQL insert row and get returning ID example: https://gist.github.com/miguelmota/d54814683346c4c98cec432cf99506c0 + err = statement.QueryRowContext(ctx, msg, clientID).Scan(&id) + if err != nil { + log.Println(err.Error()) + } + return id, err +} +// completeTrack completes an existing tracking record by setting the busy_end date +func completeTrack(ctx context.Context, db *sql.DB, id int) error { + statement, err := db.PrepareContext(ctx, `UPDATE track set busy_end=datetime(CURRENT_TIMESTAMP, 'localtime') WHERE id=(?)`) + if err != nil { + return err + } + // Golang SQL insert row and get returning ID example: https://gist.github.com/miguelmota/d54814683346c4c98cec432cf99506c0 + _, err = statement.ExecContext(ctx, id) + return err } diff --git a/main_test.go b/main_test.go index 9693812..69bbf09 100644 --- a/main_test.go +++ b/main_test.go @@ -7,10 +7,24 @@ import ( ) func Test_Tracker(t *testing.T) { + dir, err := os.MkdirTemp("", "test-") + if err != nil { + t.Fatal(err.Error()) + } + defer func(path string) { + t.Log("Removing " + path) + err := os.RemoveAll(path) + if err != nil { + t.Log(err.Error()) + } + }(dir) + dbDirectory = dir // overwrite with tempdir + checkInterval = 100 * time.Millisecond - idleAfter = 200 * time.Millisecond + idleAfter = 100 * time.Millisecond cmd = "testdata/ioreg-mock.sh" go func() { main() }() - time.Sleep(500 * time.Millisecond) + time.Sleep(1 * time.Second) c <- os.Interrupt + t.Log("Test finished") } diff --git a/sqlite.png b/sqlite.png new file mode 100644 index 0000000000000000000000000000000000000000..58d331a3c9d2cf6074b565081dad1e3d18700346 GIT binary patch literal 29611 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 literal 0 HcmV?d00001 diff --git a/sqlite/.gitignore b/sqlite/.gitignore new file mode 100644 index 0000000..f59ec20 --- /dev/null +++ b/sqlite/.gitignore @@ -0,0 +1 @@ +* \ No newline at end of file diff --git a/sqlite/.gitkeep b/sqlite/.gitkeep new file mode 100644 index 0000000..e69de29